Git Product home page Git Product logo

pyrometer's People

Contributors

brockelmore avatar ernestognw avatar inphi avatar mds1 avatar omahs avatar plotchy avatar shekhirin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyrometer's Issues

Panics while parsing yul eq

Version

pyrometer @ ed07912ff617ccdfb1255f23349d3ff0548da9de

Problem

Parsing a yul eq expression, where one of its operands is an identifer panics with a No lhs range error.
This occurs when simply running pyrometer Foo.sol, where Foo.sol:

pragma solidity ^0.8.19;

contract Foo {
    struct Struct {
        uint32 a;
    }

    function foo() public {
        Struct memory data;
        assembly {
            let x := eq(data, 0xFF)
        }
    }
}

Here's the stack trace emitted:

thread 'main' panicked at 'No lhs range', src/context/exprs/cmp.rs:183:26
stack backtrace:
   0: rust_begin_unwind
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/std/src/panicking.rs:578:5
   1: core::panicking::panic_fmt
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/panicking.rs:67:14
   2: core::panicking::panic_display
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/panicking.rs:150:5
   3: core::panicking::panic_str
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/panicking.rs:134:5
   4: core::option::expect_failed
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/option.rs:1932:5
   5: pyrometer::context::exprs::cmp::Cmp::cmp_inner
   6: pyrometer::context::exprs::cmp::Cmp::cmp_inner
             at /home/inphi/src/pyrometer/src/context/exprs/cmp.rs:160:17
   7: pyrometer::context::yul::yul_funcs::YulFuncCaller::yul_func_call::{{closure}}::{{closure}}
             at /home/inphi/src/pyrometer/src/context/yul/yul_funcs.rs:227:25
   8: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
   9: pyrometer::context::yul::yul_funcs::YulFuncCaller::yul_func_call::{{closure}}
             at /home/inphi/src/pyrometer/src/context/yul/yul_funcs.rs:218:21
  10: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  11: pyrometer::context::yul::yul_funcs::YulFuncCaller::yul_func_call
             at /home/inphi/src/pyrometer/src/context/yul/yul_funcs.rs:207:17
  12: pyrometer::context::yul::YulBuilder::parse_ctx_yul_expr_inner
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:274:44
  13: pyrometer::context::yul::YulBuilder::parse_ctx_yul_expr
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:250:13
  14: pyrometer::context::yul::YulBuilder::parse_ctx_yul_stmt_inner::{{closure}}
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:134:25
  15: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  16: pyrometer::context::yul::YulBuilder::parse_ctx_yul_stmt_inner
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:70:19
  17: pyrometer::context::yul::YulBuilder::parse_ctx_yul_stmt_inner::{{closure}}::{{closure}}
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:223:42
  18: <core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::for_each
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/slice/iter/macros.rs:204:21
  19: pyrometer::context::yul::YulBuilder::parse_ctx_yul_stmt_inner::{{closure}}
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:220:21
  20: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  21: pyrometer::context::yul::YulBuilder::parse_ctx_yul_stmt_inner
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:70:19
  22: pyrometer::context::yul::YulBuilder::parse_ctx_yul_statement
             at /home/inphi/src/pyrometer/src/context/yul/mod.rs:45:17
  23: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::{{closure}}
             at /home/inphi/src/pyrometer/src/context/mod.rs:430:21
  24: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  25: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
             at /home/inphi/src/pyrometer/src/context/mod.rs:429:27
  26: pyrometer::context::ContextBuilder::parse_ctx_statement
             at /home/inphi/src/pyrometer/src/context/mod.rs:62:33
  27: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::{{closure}}::{{closure}}
             at /home/inphi/src/pyrometer/src/context/mod.rs:260:42
  28: <core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::for_each
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/slice/iter/macros.rs:204:21
  29: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::{{closure}}
             at /home/inphi/src/pyrometer/src/context/mod.rs:258:21
  30: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  31: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
             at /home/inphi/src/pyrometer/src/context/mod.rs:257:27
  32: pyrometer::context::ContextBuilder::parse_ctx_statement
             at /home/inphi/src/pyrometer/src/context/mod.rs:62:33
  33: pyrometer::context::func_call::FuncCaller::execute_call_inner
             at /home/inphi/src/pyrometer/src/context/func_call/mod.rs:556:13
  34: pyrometer::context::func_call::FuncCaller::func_call_inner::{{closure}}
  35: pyrometer::context::ContextBuilder::apply_to_edges
             at /home/inphi/src/pyrometer/src/context/mod.rs:1504:17
  36: pyrometer::context::func_call::FuncCaller::func_call_inner
             at /home/inphi/src/pyrometer/src/context/func_call/mod.rs:490:9
  37: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
             at /home/inphi/src/pyrometer/src/context/mod.rs:222:31
  38: pyrometer::context::ContextBuilder::parse_ctx_statement
             at /home/inphi/src/pyrometer/src/context/mod.rs:71:22
  39: pyrometer::Analyzer::final_pass::{{closure}}::{{closure}}
             at /home/inphi/src/pyrometer/src/lib.rs:487:21
  40: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:853:29
  41: core::iter::traits::iterator::Iterator::fold
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:2481:21
  42: core::iter::traits::iterator::Iterator::for_each
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:856:9
  43: pyrometer::Analyzer::final_pass::{{closure}}
             at /home/inphi/src/pyrometer/src/lib.rs:485:13
  44: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:853:29
  45: core::iter::traits::iterator::Iterator::fold
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:2481:21
  46: core::iter::traits::iterator::Iterator::for_each
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/iter/traits/iterator.rs:856:9
  47: pyrometer::Analyzer::final_pass
             at /home/inphi/src/pyrometer/src/lib.rs:484:9
  48: pyrometer::Analyzer::parse
             at /home/inphi/src/pyrometer/src/lib.rs:445:21
  49: pyrometer::main
             at /home/inphi/src/pyrometer/cli/src/main.rs:218:9
  50: core::ops::function::FnOnce::call_once
             at /rustc/1a5f8bce74ee432f7cc3aa131bc3d6920e06de10/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

In the above example, I expect typical solidity behavior, where the data identifier in the eq expression is parsed as a memory offset.

Yul-based shl and shr need arg ordering swapped

Yul based shl and shr do shl(offset, value).

contract MemShifts {
    function testYulSHL() public returns (uint, uint) {
        uint x;
        uint y;
        assembly {
            x := shl(10, 1)
            y := shr(10, 1)
        }
        // assertEq(x, 1024);
        // assertEq(y, 0);
        return (x, y);
    }
}

Expect to see x == 1024 and y == 0.

image

`super` not finding functions within its namespace

Cursed inheritance chaining leads to super not finding functions in namespace

Seems to happen when inheritance 'gap' is >2 levels. Here is an example with what Ill call a 3 level 'gap', from D<>A:

abstract contract A {
    function foo() virtual public returns (uint){
        return 0;
    }
}

contract B is A {}

contract C is B {}

contract D is C {
    function foo() override public returns (uint){
        return super.foo();
    }
}

Putting foo in B or C does not produce the issue

image

Erroneous "Execution guaranteed to revert here"

latest brock/fuzz branch

Bounds that are acceptable are labeled as "Execution guaranteed to revert here".

contract A {
    function f(uint x, uint y) public pure returns (uint) {

        if (x < 2) {
            // fork true
            return 1;
        } 
        // fork false
        if (y >= 42) {
            // fork false, fork true
            return 2;
        } 
        // fork false, fork false
        return 3;
    }
}

image

Oddly, commenting the return 2; doesn't lead to this behavior

contract A {
    function f(uint x, uint y) public pure returns (uint) {

        if (x < 2) {
            // fork true
            return 1;
        } 
        // fork false
        if (y >= 42) {
            // fork false, fork true
            // return 2;
        } 
        // fork false, fork false
        return 3;
    }
}

image

Not showing all execution paths

Hey so I as testing out Pyrometer and used it against the backdoor example that the foundry fuzzer can't find in the hopes that it would pick up the constraints required to reach the execution path and show me the relevant bounds. Here is the contract code:

contract SymbolicTest {

    // https://github.com/foundry-rs/foundry/issues/2851
    function backdoor(uint256 x) external pure {
        uint256 number = 99;
        unchecked {
            uint256 z = x - 1;
            if (z == 6912213124124531) {
                number = 0;
            } else {
                number = 1;
            }
        }
        assert(number != 0);
    }

}

My terminal output

~/repositories/personal/forge-playground main ❯ pyrometer ./contracts/SymbolicTest.sol -vv                                          system
DONE ANALYZING IN: 1ms. Writing to cli...
Bounds: Bounds for function: function backdoor(uint256)
Bounds: Bounds for subcontext: backdoor(uint256) where:
1. (number != 0) == true
2. (z != 6912213124124531) == true
, killed: None
    ╭─[./contracts/SymbolicTest.sol:7:48]
    │
  7 │ ╭─▶     function backdoor(uint256 x) external pure {
  8 │ │           uint256 number = 99;
    │ │           ─────────┬─────────
    │ │                    ╰─────────── "number" == 99
    ┆ ┆
 10 │ │               uint256 z = x - 1;
    │ │               ────────┬────────
    │ │                       ╰────────── "z" ∈ [ 2**256 - 2, 2**256 - 1 ]
 11 │ │               if (z == 6912213124124531) {
    │ │                   ┬
    │ │                   ╰── "z" ∈ [ 2**256 - 2, 2**256 - 1 ] && ∉ { == 6912213124124531}
    ┆ ┆
 14 │ │                   number = 1;
    │ │                   ───┬──
    │ │                      ╰──── "number" == 1
    ┆ ┆
 18 │ ├─▶     }
    │ │
    │ ╰─────────── Entry function call

I would have expected a second trace where the constraint (z != 6912213124124531) == true isn't applied.

Note I did take the assert statement out and tried as well with the same result.

Is this just a limitation of the current implementation? Just trying to understand, I know halmos picks up the counter example value.

Node type confusion: expected node to be ContextVar but it was: Builtin(Uint(256))

example solidity:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Sample {
	uint256[49] private __gap;
}

run command:

pyrometer Sample.sol -v

out:

DONE ANALYZING IN: 0ms. Writing to cli...
Error: Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer
   ╭─[Sample.sol:5:2]
   │
 5 │     uint256[49] private __gap;
   │     ─────┬─────  
   │          ╰─────── Node type confusion: expected node to be ContextVar but it was: Builtin(Uint(256))
───╯

Graph IR Error: Node type confusion

Running pyrometer in toucanprotocol/contracts and one issue I am seeing:

$ pyrometer -vv -r remappings.txt contracts/RetirementCertificates.sol
[ ... ]
Error: Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer
    ╭─[node_modules/@openzeppelin/contracts-upgradeable/access/../utils/ContextUpgradeable.sol:36:5]

 36 │     uint256[50] private __gap;
    │     ─────┬─────  
    │          ╰─────── Node type confusion: expected node to be ContextVar but it was: Builtin(Uint(256))

tread 'main' panicked - pyrometer ./src/name.sol

thread 'main' panicked at 'called Result::unwrap()on anErrvalue: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/lib.rs:401:61 note: run withRUST_BACKTRACE=1 environment variable to display a backtrace

The file exist.

Constructor inheritance chaining leads to `Detached Function` errors

Chaining constructor syntax leads to panic

contract A {
    address a;
    constructor(address _a) {
        a = _a;
    }
}

contract B is A {
    constructor(address _a) A(_a) {}
}

contract C is B {
    constructor(address _a) B(_a) {}
}

contract X {
    address x;
    constructor(address _x) {
        x = _x;
    }
}

abstract contract Y is X {
    constructor(address _x) {} // abstract doesnt need to init bases
}

contract D is Y, C {
    constructor(address _a) Y(_a) X(_a) C(_a) {} // inheriting abstract leads to needing to explicitly init the bases here
}
❯ pyrometer src/constructor.sol 
thread 'main' panicked at 'Detached function: constructor(address)', ../code/packages/pyrometer/shared/src/nodes/func_ty.rs:237:36
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

https://docs.soliditylang.org/en/v0.8.20/contracts.html#multiple-inheritance-and-linearization

Instalation issue

When following the installation instructions, I get the error:

[I] ➜ cargo install --path . --locked

warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   pyrometer/cli/Cargo.toml
workspace: pyrometer/Cargo.toml
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   pyrometer/cli/Cargo.toml
workspace: pyrometer/Cargo.toml
  Installing cli v0.1.0 (pyrometer/cli)
    Updating git repository `https://github.com/brockelmore/ariadne`
error: failed to load source for dependency `ariadne`

Caused by:
  Unable to update https://github.com/brockelmore/ariadne#c2e3a8e7

Caused by:
  failed to clone into: .cargo/git/db/ariadne-44ade852abe2148c

Caused by:
  failed to authenticate when downloading repository: [email protected]:brockelmore/ariadne

  * attempted ssh-agent authentication, but no usernames succeeded: `git`

  if the git CLI succeeds then `net.git-fetch-with-cli` may help here
  https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli

Caused by:
  no authentication methods succeeded

Add Vyper Support

The plan is to use Vypers IR and convert accordingly. I don't have the bandwidth to implement it on my own right now, but I opened the issue to have a place for this discussion.

NPM support

Hi, I notice that pyrometer would parse all the dependencies used by import. And in some projects, the dependencies may comes from npm or other package managers. If there is a need for support for import statements starts with "@", I can try to implement this and send a pull request to this repo.

There is an example

// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../shared/ProtocolConstants.sol";

contract XVader is ProtocolConstants, ERC20Votes, ReentrancyGuard {
    // Address of vader token
    IERC20 public immutable vader;

    /*
     * @dev Initializes contract's state by setting vader's tokens address and
     * setting current token's name and symbol.
     **/
    constructor(IERC20 _vader)
        ERC20Permit("XVader")
        ERC20("XVader", "xVADER")
    {
        require(
            _vader != IERC20(_ZERO_ADDRESS),
            "XVader::constructor: _vader cannot be a zero address"
        );
        vader = _vader;
    }
......

Constraints on constants/immutables in functions are pessimistic rather than exact

Constants and immutable variables have range [0, 2**256-1]

pragma solidity ^0.8.19;

contract constant_fold {
    uint constant N = 2_000_000;
    // uint immutable N = 2_000_000;

    function f(uint x) public returns (uint) {
        if (x == N / 2) {
            return 1;
        }
        return 2;
    }
}

Would expect x == 1_000_000 inside the if.

Bounds: Bounds for function: function f(uint256)
Bounds: Bounds for subcontext: f(uint256).fork{ true }.resume{ f(uint256) } where:
1. (x == (N / 2)) == true

    ╭─[src/constant_fold.sol:7:46]
    │
  7 │ ╭─▶     function f(uint x) public returns (uint) {
  8 │ │           if (x == N / 2) {
    │ │               ─────┬────  
    │ │                    ╰────── "x" ∈ [ 0, 2**255 - 1 ]
  9 │ │               return 1;
    │ │               ────┬───  
    │ │                   ╰───── returns: "1" == 1
    ┆ ┆   
 12 │ ├─▶     }
    │ │           
    │ ╰─────────── Function call

No range available for var in `require` when using yul `eq()`

Unsure how this error manifests. Providing some behavior I noticed below. Seems to be happen when eq() is used in conjunction with and or or.

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
library lib {

    function foo(
        address a
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            success := and(eq(a, 0), call(gas(), a, 4, 5, 6, 7, 8)) //error
            // success := or(eq(a, 0), call(gas(), a, 4, 5, 6, 7, 8)) //error
            // success := eq(eq(a, 0), call(gas(), a, 4, 5, 6, 7, 8)) //ok
            // success := and(1, call(gas(), a, 4, 5, 6, 7, 8)) //ok, no eq


        }
        require(success);
    }
}
image

Propagate bounds across untouched memory when dealing with inline assembly

Bounds can be propagated when memory is untouched and variables are stored and loaded at the same positions.

contract Bound {
    function mask(uint256 a) public payable returns (uint) {
        uint256 b = a & 0xff;
        uint256 c;
        assembly {
            // store b and load into c
            let free_mem := mload(0x40)
            mstore(free_mem, b)
            c := mload(free_mem)
        }
        // range context is lost
        return c;
    }
}

Would expect c to share bounds with b

  4 │ ╭─▶     function mask(uint256 a) public payable returns (uint) {
  5 │ │           uint256 b = a & 0xff;
    │ │           ──────────┬─────────  
    │ │                     ╰─────────── "b" ∈ [ 0, 255 ]
    ┆ ┆   
 14 │ │           return c;
    │ │           ────┬───  
    │ │               ╰───── returns: "c" ∈ [ 0, 2**256 - 1 ]
 15 │ ├─▶     }
    │ │           
    │ ╰─────────── Entry function call

Seems difficult to track untouched memory with operations in between that touch memory (ie: codecopy, calldatacopy, etc). Are dest, offset of those tracked?

Cannot disambiguate functions - Inheritance/ContractType

abstract contract YInterface {
    function foo() virtual external returns (uint);
}

contract Y is YInterface {
    function foo() virtual override public returns (uint) {
        return 1;
    }

    function bar(Y y) internal {
        y.foo();
    }
}
image

On the other hand, this is ok:

contract Y {
    function foo() virtual public returns (uint) {
        return 1;
    }

    function bar(Y y) internal {
        y.foo();
    }
}

Thinking extra layer with the virtual fn in the inherited interface matters.

Assembly combination of `if`, `eq`, and fn param leads to panic

Looking at the ok statements, seems that the combo of the 3 (if, eq, input param) makes this an issue.

contract solady_erc20 {

    function foo(address a) public {
        assembly {
            if eq(0x0, a) {}    // bad
            // if eq(0x0, 0x1) {}  // ok
            // let b:= eq(0x0, a)  // ok
        }
    }
}
thread 'main' panicked at 'here Eq', src/context/exprs/require.rs:1427:26

Add support for remappings.txt

Given the following setup:

forge init
forge install transmissions11/solmate

and the following contract in src/BasicERC721.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import {ERC721} from "solmate/tokens/ERC721.sol";

contract BasicERC721 is ERC721 {
    constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {}

    function mint(address ptr) public {
        _mint(ptr, 1);
    }

    function tokenURI(uint256) public view virtual override returns (string memory) {
        return "tokenURI";
    }
}

We get the following error:

pyrometer src/BasicSS2ERC721.sol
thread 'main' panicked at 'Could not find file for dependency: "solmate/tokens/ERC721.sol"'

Ideally, pyrometer should be able to parse the following remappings.txt and do the substitution:

solmate/=lib/solmate/src/

Range calculation for div seems to always be 1

Would expect x == 1_000_000 inside the if, however it becomes x == 1

pragma solidity ^0.8.19;

contract constant_fold {
    uint N;

    function f(uint x) public returns (uint) {
        N = 2_000_000;
        if (x == N / 2) {
            return 1;
        }
        return 2;
    }
}

Notice constraint number 2, seems that the numerator is also the denominator.

Bounds: Bounds for function: function f(uint256)
Bounds: Bounds for subcontext: f(uint256).fork{ true }.resume{ f(uint256) } where:
1. (N != 0) == true
2. (x == (N / N)) == true

    ╭─[src/constant_fold.sol:6:46]
    │
  6 │ ╭─▶     function f(uint x) public returns (uint) {
  7 │ │           N = 2_000_000;
    │ │           ──────┬──────  
    │ │                 ╰──────── Storage var "N" == 2000000
  8 │ │           if (x == N / 2) {
    │ │               ─────┬────  
    │ │                    ╰────── "x" == 1
  9 │ │               return 1;
    │ │               ────┬───  
    │ │                   ╰───── returns: "1" == 1
    ┆ ┆   
 12 │ ├─▶     }
    │ │           
    │ ╰─────────── Function call

(I know there's a lot of rearchitecting rn, just want to document and give a ex)

Solidity `hex""` should be represented as `bytes`, not `bytes1`

This has implications when using low level calls and trying to hit fallbacks or receives

contract A {

    function foo() public {
        address a = address(0);
        a.call(hex"");
        a.delegatecall(hex"");

        bytes memory data = hex"01234567";
    }
}

Notice that member access is looking for call(bytes1) and delegatecall(bytes1)
image

Support for relative imports in libraries

Given the contract:

import {AccessControlEnumerableUpgradeablee} from "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlEnumerableUpgradeable.sol";

contract MyContract is AccessControlEnumerableUpgradeable {

With the directory structure:

lib/
   openzeppelin..../
        contracts/
           access/
               AccessControlEnumerableUpgradeable.sol
src/
    MyContract.sol

OZ defines imports in the lib as:

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerableUpgradeable.sol";
import "./AccessControlUpgradeable.sol";
import "../utils/structs/EnumerableSetUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable {
    function __AccessControlEnumerable_init() internal onlyInitializing {

Pyrometer panics with thread 'main' panicked at 'Could not find file for dependency: "./IAccessControlEnumerableUpgradeable.sol"'

Could be wrong but I believe this is an issue with relative imports in libraries.

Node confusion on `Expected variable type to be concrete`

Not sure what the root cause is here. Doesn't seem to be about disambiguity, though commenting either of the internal fns removes the error, so somehow the signatures would be colliding?

contract solady_erc721 {

    function foo(address from, address to, uint256 id) public {
        foo(from, to, id, 0);
    }

    function foo(address from, address to, uint256 id, uint num) internal {}

    function foo(address by, address from, address to, uint256 id) internal {}
}
2023-05-23T17:12:55.055133Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_expr_inner{ctx=foo(address, address, uint256)}:fn_call_expr:call_internal_func:pop_expr_latest: shared::context: popping var [from, to, id, 0] from: foo(address, address, uint256)
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NodeConfusion("Expected variable type to be concrete but was: BuiltIn(BuiltInNode(0), Some(SolcRange { min: Concrete(RangeConcrete { val: Uint(256, 0), loc: Implicit }), min_cached: None, max: Concrete(RangeConcrete { val: Uint(256, 115792089237316195423570985008687907853269984665640564039457584007913129639935), loc: Implicit }), max_cached: None, exclusions: [] }))")', src/context/func_call/mod.rs:151:84

Failed to be concrete with yul `or()`

Spent some time simplifying the expression, left the parents commented in case it's useful for testing.

Seems to be caused by this expression require: (a | 0) > 0 failing to be concrete

contract conc_range {
    function foo(address a) internal virtual {
        assembly {
            {
                // if iszero(or(iszero(a), or(eq(a, 0x0), eq(a, 0x0)))) {} // bad
                // if iszero(or(iszero(a), or(0x0, 0x0))) {} // bad
                // if iszero(or(iszero(a), 0x0)) {} // bad
                // if iszero(or(a, 0x0)) {} // bad
                if or(a, 0x0) {} // bad
                // if a {} // ok
            }
        }
    }
}
2023-05-23T17:40:40.665609Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_yul_statement{ctx=foo(address)}:parse_ctx_yul_stmt_inner:parse_ctx_yul_stmt_inner:parse_ctx_yul_stmt_inner:yul_cond_op_stmt:require: pyrometer::context::exprs::require: require: (a | 0) > 0
2023-05-23T17:40:40.665636Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_yul_statement{ctx=foo(address)}:parse_ctx_yul_stmt_inner:parse_ctx_yul_stmt_inner:parse_ctx_yul_stmt_inner:yul_cond_op_stmt:require:update_nonconst_from_const: pyrometer::context::exprs::require: Setting range for nonconst from const
thread 'main' panicked at 'Was not concrete', src/context/exprs/require.rs:938:53

Implement `gasleft`

I'm currently playing around with the tool and observed that gasleft is not yet implemented. I assume you track this somewhere, but I figured that I would still open an issue to track it properly.

thread 'main' panicked at 'not yet implemented: builtin function: "gasleft"', C:\dev\fun\pyrometer\src\context\func.rs:157:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

No associated contract for context error

Crashing when run on https://testnet.arbiscan.io/address/0x741654C43DC0562958E0b3c172F93f4bd54400F9#code (flat)

pyrometer -vvvvv ./SubaccountFactory.sol 
thread 'main' panicked at 'No associated contract for context', /Users/d/dehat/src/pyrometer/shared/src/context/mod.rs:222:14
stack backtrace:
   0:        0x104bf3ebc - std::backtrace_rs::backtrace::libunwind::trace::h8787edacd429d828
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:        0x104bf3ebc - std::backtrace_rs::backtrace::trace_unsynchronized::h7a9846606490caa8
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:        0x104bf3ebc - std::sys_common::backtrace::_print_fmt::h95438bed72312512
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:65:5
   3:        0x104bf3ebc - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h1027694b54c428d0
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:44:22
   4:        0x104c09ed8 - core::fmt::write::hb60cc483d75d6594
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/fmt/mod.rs:1213:17
   5:        0x104bf18bc - std::io::Write::write_fmt::h6c907fc10bdb865b
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/io/mod.rs:1682:15
   6:        0x104bf3cd0 - std::sys_common::backtrace::_print::h323796fb767df5e0
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:47:5
   7:        0x104bf3cd0 - std::sys_common::backtrace::print::h1a62458f14dd2797
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:34:9
   8:        0x104bf532c - std::panicking::default_hook::{{closure}}::h03c6918072c36210
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:267:22
   9:        0x104bf5084 - std::panicking::default_hook::hd0f3cf66b6a0fb5e
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:286:9
  10:        0x104bf5950 - std::panicking::rust_panic_with_hook::h9ed2a7a45efbd034
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:688:13
  11:        0x104bf5770 - std::panicking::begin_panic_handler::{{closure}}::h535244d6186e3534
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:579:13
  12:        0x104bf4324 - std::sys_common::backtrace::__rust_end_short_backtrace::ha542aa49031c5cb5
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:137:18
  13:        0x104bf54cc - rust_begin_unwind
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:575:5
  14:        0x104c17514 - core::panicking::panic_fmt::hc1e7b11add95109d
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/panicking.rs:64:14
  15:        0x104c08fe4 - core::panicking::panic_display::h4f6a6d9c90c2a577
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/panicking.rs:147:5
  16:        0x104c08fa8 - core::panicking::panic_str::h093e45861a4f3940
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/panicking.rs:131:5
  17:        0x104c174e0 - core::option::expect_failed::h13082a32d0e23cf7
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/option.rs:1924:5
  18:        0x104a9c198 - shared::context::ContextNode::associated_contract::h29c7bbbb1891bb7d
  19:        0x104a8ada8 - pyrometer::context::ContextBuilder::parse_ctx_expr::hb2cd7871a654ff4f
  20:        0x104a67428 - pyrometer::context::func::FuncCaller::intrinsic_func_call::hc4a69e758636217f
  21:        0x104a8b9e8 - pyrometer::context::ContextBuilder::parse_ctx_expr::hb2cd7871a654ff4f
  22:        0x104acf550 - <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter::h4212837b07f4a57f
  23:        0x104a8b814 - pyrometer::context::ContextBuilder::parse_ctx_expr::hb2cd7871a654ff4f
  24:        0x104a887c4 - pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::he163909ed75e91b7
  25:        0x104a87ca8 - pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::hd6e6110af1f15840
  26:        0x104a696d0 - pyrometer::context::func::FuncCaller::execute_call_inner::h8a3c5e3f2c0f97b2
  27:        0x104a68cd0 - pyrometer::context::func::FuncCaller::func_call_inner::h0603424edc9566cd
  28:        0x104a865dc - pyrometer::context::ContextBuilder::parse_ctx_stmt_inner::hbc500f51158ad4e5
  29:        0x104a8f948 - pyrometer::Analyzer::parse::h38ee9fc978d60b29
  30:        0x104a0b710 - pyrometer::main::h8ea434558af1757b
                               at /Users/d/dehat/src/pyrometer/cli/src/main.rs:119:42
  31:        0x104a4613c - core::ops::function::FnOnce::call_once::h095888031204766b
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/ops/function.rs:250:5
  32:        0x104a4613c - std::sys_common::backtrace::__rust_begin_short_backtrace::h020feb58b0580f9e
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/sys_common/backtrace.rs:121:18
  33:        0x1049fb2f0 - std::rt::lang_start::{{closure}}::h822ff7b8425f1b04
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/rt.rs:166:18
  34:        0x104beda68 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::h602b6f29451c74c7
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/ops/function.rs:287:13
  35:        0x104beda68 - std::panicking::try::do_call::h8ad76c1527a3892b
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:483:40
  36:        0x104beda68 - std::panicking::try::hbfc990f7ac38d34c
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:447:19
  37:        0x104beda68 - std::panic::catch_unwind::h936bb5789e0b4241
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panic.rs:140:14
  38:        0x104beda68 - std::rt::lang_start_internal::{{closure}}::h896fa40a3ab062d0
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/rt.rs:148:48
  39:        0x104beda68 - std::panicking::try::do_call::h21fb8583a42bdaac
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:483:40
  40:        0x104beda68 - std::panicking::try::h90121103ee57470a
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:447:19
  41:        0x104beda68 - std::panic::catch_unwind::hfd5c7b5d06b8f149
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panic.rs:140:14
  42:        0x104beda68 - std::rt::lang_start_internal::h9f0566e553deb11e
                               at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/rt.rs:148:20
  43:        0x104a10b78 - _main

Execution ordering in tuples and assignments is off

pragma solidity >=0.8.0;
contract struct_push {

    mapping(uint => uint) map;
    uint public index;
    uint public a;

    function foo() public payable returns (uint, uint, uint, uint, uint) {
        require(index == 0);
        (a, map[++index]) = (index, bar(++index));
        
        return (a, index, map[0], map[1], map[2]);
    }

    function bar(uint i) internal pure returns (uint) {
        return i;
    }
}

Foundry output of foo():

Running 1 test for test/any.t.sol:CounterTest
[PASS] testPush() (gas: 54875)
Traces:
  [172906] CounterTest::setUp() 
    ├─ [118365] → new struct_push@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   └─ ← 591 bytes of code
    └─ ← ()

  [54875] CounterTest::testPush() 
    ├─ [49591] struct_push::foo() 
    │   └─ ← 0, 2, 0, 0, 1
    └─ ← ()

Test result: ok. 1 passed; 0 failed; finished in 248.38µs

Pyrometer output of foo():
image

a == 1, though is expected to be 0.
map[2] == [0, 2^256-1] and is expected to be 1. Though all the mapping slots are pessimistic so this seems currently unsupported.

Expected single expr evaluation of index expression

Version:

➜ pyrometer --version
cli 0.1.0

Issue

This line in our repo triggers an error.

Error: Unexpected type as array index
     ╭─[contracts/L1/L2OutputOracle.sol:296:16]
     │
 296 │         return l2Outputs[getL2OutputIndexAfter(_l2BlockNumber)];
     │                ────────────────────────┬───────────────────────
     │                                        ╰───────────────────────── Expected single expr evaluation of index expression, but was: (Single(NodeIndex(2871)), Multi([Single(NodeIndex(2864))])). This is a bug. Please report it at github.com/nascentxyz/pyrometer.

The command I'm using is:

cd packages/contracts-bedrock
pyrometer contracts/L1/L2OutputOracle.sol --remappings remappings.txt

Repro

A minimal test case is:

contract Test28 is Test {
  bytes32[] public arr;

  constructor() {
    arr.push(hex"1234");
    arr.push(hex"5678");
  }

  function getNum() public pure returns (uint256) {
    return 1;
  }

  function test_pyrobug() external returns (bytes32) {
    return arr[getNum()];
  }
}

show error for flatten contract

thread 'main' panicked at 'not yet implemented', ~/pyrometer/src/lib.rs:382:30
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic
   3: pyrometer::Analyzer::parse_contract_def::{{closure}}
   4: <core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::for_each
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/slice/iter/macros.rs:211:21
   5: pyrometer::Analyzer::parse_contract_def
             at ~/pyrometer/src/lib.rs:352:9
   6: pyrometer::Analyzer::parse_source_unit_part
             at ~/pyrometer/src/lib.rs:259:37
   7: pyrometer::Analyzer::parse_source_unit::{{closure}}
             at ~/pyrometer/src/lib.rs:230:37
   8: core::iter::traits::iterator::Iterator::for_each::call::{{closure}}
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/iter/traits/iterator.rs:828:29
   9: <core::iter::adapters::enumerate::Enumerate<I> as core::iter::traits::iterator::Iterator>::fold::enumerate::{{closure}}
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/iter/adapters/enumerate.rs:106:27
  10: core::iter::traits::iterator::Iterator::fold
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/iter/traits/iterator.rs:2414:21
  11: <core::iter::adapters::enumerate::Enumerate<I> as core::iter::traits::iterator::Iterator>::fold
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/iter/adapters/enumerate.rs:112:9
  12: core::iter::traits::iterator::Iterator::for_each
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/iter/traits/iterator.rs:831:9
  13: pyrometer::Analyzer::parse_source_unit
             at ~/pyrometer/src/lib.rs:225:9
  14: pyrometer::Analyzer::parse
             at ~/pyrometer/src/lib.rs:189:29
  15: pyrometer::main
             at ~/pyrometer/cli/src/main.rs:119:42
  16: core::ops::function::FnOnce::call_once
             at /private/tmp/rust-20230210-6343-w92jca/rustc-1.67.1-src/library/core/src/ops/function.rs:507:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

`Unresolved` with calls to virtual fn.

Similar to #38 but found the issue at additional contexts:

  • fn at state-var-type
  • fn at calldata-type
abstract contract A {
    function foo() virtual external returns (uint) {}
}

abstract contract B is A {
    A a;
    function liquidateBorrowInternal(A _a) internal returns (uint, uint) {
        // uint b = foo();
        uint b2 = _a.foo();
        uint b3 = a.foo();
        // if (b != 1) {}
        if (b2 != 1) {}
        if (b3 != 1) {}

        return (b2, b3);
    }

    function foo() public virtual override returns (uint){
        return 1;
    }
}
image

Calls to contract-type state variables becomes `Unresolved`

interface B {
    function baz() external returns (uint);
}
contract A {
    B public b;
    function _setB(B _b) internal {
        b.baz(); // commenting this removes error
        b = _b;
    }
}

Title may be inaccurate. The assignment of _b to b fails when you call the .baz() member on b.

image

Unreachable warnings

Installed the latest cargo install --path . --locked beta release (0cfae6f) and got the following warnings. Opening this issue to simply track those and don't forget about it.

warning: unreachable call
   --> shared\src\context\mod.rs:964:22
    |
964 |               e => Err(GraphError::NodeConfusion(panic!(
    |  ______________________^^^^^^^^^^^^^^^^^^^^^^^^^_-
    | |                      |
    | |                      unreachable call
965 | |                 "Node type confusion: expected node to be Context but it was: {e:?}"
966 | |             ))),
    | |_____________- any code following this expression is unreachable
    |
    = note: `#[warn(unreachable_code)]` on by default

   Compiling pyrometer v0.1.0 (C:\Dev\Blockchain\pyrometer)
warning: unreachable statement
    --> src\context\mod.rs:1055:21
     |
1054 |                     todo!("{ty:?}");
     |                     --------------- any code following this expression is unreachable
1055 |                     ctx.push_expr(ExprRet::Null, self).into_expr_err(*loc)?;
     |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable statement
     |
     = note: `#[warn(unreachable_code)]` on by default

warning: unreachable call
    --> src\context\mod.rs:1378:24
     |
1378 |               return Err(ExprErr::GraphError(
     |                          ^^^^^^^^^^^^^^^^^^^ unreachable call
...
1381 | /                 panic!(
1382 | |                     "Variable update of {} in old context: parent: {}, child: {:#?}",
1383 | |                     cvar_node.display_name(self).unwrap(),
1384 | |                     ctx.path(self),
1385 | |                     child
1386 | |                 ), //),
     | |_________________- any code following this expression is unreachable

warning: unused import: `itertools::Itertools`
 --> src\context\func_call\mod.rs:8:5
  |
8 | use itertools::Itertools;
  |     ^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `CodeLocation`
  --> src\context\analyzers\bounds.rs:15:25
   |
15 | use solang_parser::pt::{CodeLocation, StorageLocation};
   |                         ^^^^^^^^^^^^

warning: unused import: `analyzer::AnalyzerLike`
 --> src\context\analyzers\bounds.rs:9:5
  |
9 |     analyzer::AnalyzerLike,
  |     ^^^^^^^^^^^^^^^^^^^^^^

warning: unused import: `shared::analyzer::AnalyzerLike`
 --> src\context\analyzers\var_analyzer\report_display.rs:3:5
  |
3 | use shared::analyzer::AnalyzerLike;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: `shared` (lib) generated 1 warning
warning: `pyrometer` (lib) generated 6 warnings

assertion failed: input_exprs.len() == 2

Getting this error when trying to analyze a specific contract in toucanprotocol/contracts:

$ pyrometer -vv -r remappings.txt contracts/CarbonOffsetBatches.sol 
thread 'main' panicked at 'assertion failed: input_exprs.len() == 2', src/context/func_call/intrinsic_call.rs:201:29
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

.balance member access is unhandled

I have this when running on the $SAFEMOON contract:
https://bscscan.deth.net/address/0x8e7877fe58bc2a979692862df9e84e1bf7ec94ae
(contract is already flattened)

thread 'main' panicked at 'Unknown member access on address: "balance"', src/context/exprs/member_access.rs:576:30
stack backtrace:
0: rust_begin_unwind
at /rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/std/src/panicking.rs:579:5
1: core::panicking::panic_fmt
at /rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/core/src/panicking.rs:64:14
2: pyrometer::context::exprs::member_access::MemberAccess::builtin_member_access
3: pyrometer::context::exprs::member_access::MemberAccess::member_access
4: pyrometer::context::ContextBuilder::parse_ctx_expr
5: pyrometer::context::exprs::require::Require::handle_require
6: pyrometer::context::func_call::intrinsic_call::IntrinsicFuncCaller::intrinsic_func_call
7: pyrometer::context::func_call::FuncCaller::fn_call_expr
8: pyrometer::context::ContextBuilder::parse_ctx_expr
9: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
10: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
11: pyrometer::context::func_call::FuncCaller::execute_call_inner
12: pyrometer::context::func_call::FuncCaller::func_call_inner
13: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
14: pyrometer::Analyzer::final_pass
15: pyrometer::Analyzer::parse
16: pyrometer::main
at /home/cergyketh/dev/evm/external/pyrometer/cli/src/main.rs:137:9
17: core::ops::function::FnOnce::call_once
at /rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/core/src/ops/function.rs:250:5

Maybe the native .balance access is not handled?

thread 'main' panicked at 'Expected single expr evaluation of index expression

cli 0.1.0
cmd:
pyrometer <path>/ConstantProduct2-Flat.sol

Flattened solidity file (.txt to support upload here): ConstantProduct2-Flat.sol.txt

Output:

ctx: calcReserve(uint256[], uint256, uint256, bytes), Assign(File(0, 15404, 15448), Variable(Identifier { loc: File(0, 15404, 15411), name: "reserve" }), Divide(File(0, 15414, 15448), Power(File(0, 15414, 15432), Variable(Identifier { loc: File(0, 15414, 15427), name: "lpTokenSupply" }), NumberLiteral(File(0, 15431, 15432), "2", "", None)), Variable(Identifier { loc: File(0, 15435, 15448), name: "EXP_PRECISION" })))
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15404, 15411), name: "reserve" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), Divide(File(0, 15414, 15448), Power(File(0, 15414, 15432), Variable(Identifier { loc: File(0, 15414, 15427), name: "lpTokenSupply" }), NumberLiteral(File(0, 15431, 15432), "2", "", None)), Variable(Identifier { loc: File(0, 15435, 15448), name: "EXP_PRECISION" }))
ctx: calcReserve(uint256[], uint256, uint256, bytes), Power(File(0, 15414, 15432), Variable(Identifier { loc: File(0, 15414, 15427), name: "lpTokenSupply" }), NumberLiteral(File(0, 15431, 15432), "2", "", None))
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15414, 15427), name: "lpTokenSupply" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), NumberLiteral(File(0, 15431, 15432), "2", "", None)
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15435, 15448), name: "EXP_PRECISION" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), Assign(File(0, 15458, 15521), Variable(Identifier { loc: File(0, 15458, 15465), name: "reserve" }), FunctionCall(File(0, 15468, 15521), MemberAccess(File(0, 15468, 15486), Variable(Identifier { loc: File(0, 15468, 15475), name: "LibMath" }), Identifier { loc: File(0, 15476, 15486), name: "roundedDiv" }), [Variable(Identifier { loc: File(0, 15487, 15494), name: "reserve" }), ArraySubscript(File(0, 15496, 15520), Variable(Identifier { loc: File(0, 15496, 15504), name: "reserves" }), Some(ConditionalOperator(File(0, 15505, 15519), Equal(File(0, 15505, 15511), Variable(Identifier { loc: File(0, 15505, 15506), name: "j" }), NumberLiteral(File(0, 15510, 15511), "1", "", None)), NumberLiteral(File(0, 15514, 15515), "0", "", None), NumberLiteral(File(0, 15518, 15519), "1", "", None))))]))
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15458, 15465), name: "reserve" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), FunctionCall(File(0, 15468, 15521), MemberAccess(File(0, 15468, 15486), Variable(Identifier { loc: File(0, 15468, 15475), name: "LibMath" }), Identifier { loc: File(0, 15476, 15486), name: "roundedDiv" }), [Variable(Identifier { loc: File(0, 15487, 15494), name: "reserve" }), ArraySubscript(File(0, 15496, 15520), Variable(Identifier { loc: File(0, 15496, 15504), name: "reserves" }), Some(ConditionalOperator(File(0, 15505, 15519), Equal(File(0, 15505, 15511), Variable(Identifier { loc: File(0, 15505, 15506), name: "j" }), NumberLiteral(File(0, 15510, 15511), "1", "", None)), NumberLiteral(File(0, 15514, 15515), "0", "", None), NumberLiteral(File(0, 15518, 15519), "1", "", None))))])
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15468, 15475), name: "LibMath" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15487, 15494), name: "reserve" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), ArraySubscript(File(0, 15496, 15520), Variable(Identifier { loc: File(0, 15496, 15504), name: "reserves" }), Some(ConditionalOperator(File(0, 15505, 15519), Equal(File(0, 15505, 15511), Variable(Identifier { loc: File(0, 15505, 15506), name: "j" }), NumberLiteral(File(0, 15510, 15511), "1", "", None)), NumberLiteral(File(0, 15514, 15515), "0", "", None), NumberLiteral(File(0, 15518, 15519), "1", "", None))))
ctx: calcReserve(uint256[], uint256, uint256, bytes), Variable(Identifier { loc: File(0, 15496, 15504), name: "reserves" })
ctx: calcReserve(uint256[], uint256, uint256, bytes), ConditionalOperator(File(0, 15505, 15519), Equal(File(0, 15505, 15511), Variable(Identifier { loc: File(0, 15505, 15506), name: "j" }), NumberLiteral(File(0, 15510, 15511), "1", "", None)), NumberLiteral(File(0, 15514, 15515), "0", "", None), NumberLiteral(File(0, 15518, 15519), "1", "", None))
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.0, NumberLiteral(File(0, 15514, 15515), "0", "", None)
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.0, Variable(Identifier { loc: File(0, 15505, 15506), name: "j" })
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.0, NumberLiteral(File(0, 15510, 15511), "1", "", None)
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.1, NumberLiteral(File(0, 15518, 15519), "1", "", None)
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.1, Variable(Identifier { loc: File(0, 15505, 15506), name: "j" })
ctx: calcReserve(uint256[], uint256, uint256, bytes).fork.1, NumberLiteral(File(0, 15510, 15511), "1", "", None)
thread 'main' panicked at 'Expected single expr evaluation of index expression, but was: (Single((ContextNode(129), NodeIndex(152))), Fork(SingleLiteral((ContextNode(153), NodeIndex(157))), SingleLiteral((ContextNode(154), NodeIndex(167))))). This is a bug. Please report it at github.com/nascentxyz/pyrometer.', src/context/exprs/array.rs:96:18
stack backtrace:
   0: rust_begin_unwind
             at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/std/src/panicking.rs:575:5
   1: core::panicking::panic_fmt
             at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/panicking.rs:64:14
   2: pyrometer::context::exprs::array::Array::index_into_array_inner
   3: pyrometer::context::exprs::array::Array::index_into_array
   4: pyrometer::context::ContextBuilder::parse_ctx_expr
   5: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
   6: pyrometer::context::func::FuncCaller::fn_call_expr
   7: pyrometer::context::ContextBuilder::parse_ctx_expr
   8: pyrometer::context::ContextBuilder::assign_exprs
   9: pyrometer::context::ContextBuilder::parse_ctx_expr
  10: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
  11: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
  12: pyrometer::context::func::FuncCaller::execute_call_inner
  13: pyrometer::context::func::FuncCaller::func_call_inner
  14: pyrometer::context::ContextBuilder::parse_ctx_stmt_inner
  15: pyrometer::Analyzer::parse
  16: pyrometer::main
             at ./src/main.rs:119:42
  17: core::ops::function::FnOnce::call_once
             at /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.