Open moonhyeonah opened 4 years ago
The two values in question (276069... and 640204...) are concretizations of symbolic values, meaning that the number displayed isn't the one-and-only canonical value, just a possibility that Z3 found. I think what's happening when we generate the debug trace is this:
symbolic_val
as an argument to transfer
. We ask Z3 for a concrete value (for the sake of the trace) and it gives us 276069...symbolic_val
balance
on symbolic_to
. The result is the symbol from step 2. Manticore knows that this should have the same value as symbolic_val
, but it has "forgotten" about the previously concretized value for symbolic_val
because we only generated it for the debug trace. Therefore, when it asks Z3 for the concretized value, it will most likely get a different possible value. To confirm that this is what's happening, you could try constraining symbolic_val
to some specific value at the start of execution and seeing whether you still get the unexpected result. @feliam does the above look right to you? Perhaps, for usability's sake, we could consider constraining symbols to be equal to their first concretized value whenever we generate the debug traces.
Your thinking at the end seems sound to me:
state.constrain(Operators.UGT(balance_after, balance_before))
if state.is_feasible():
print("Bug found! see {}".format(m.workspace))
In general, using the solver to check whether the property you want holds on your symbols will be more effective than concretizing the values and checking them manually.
@moonhyeonah thank you for reporting this! @ehennenfent thank you for looking into this!
Yes it looks like the example solution/concretization is not locked into the path constraint so calling the solver different times to get different concrete parts of the state refer to different solution set.
We need a contraint=True
here: https://github.com/trailofbits/manticore/blob/d29bf0c3151deb500579bf0ae578ef8dfe8d4363/manticore/ethereum/manticore.py#L1601
And in some other places too. This needs some rework.
OS / Environment
No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.3 LTS Release: 18.04 Codename: bionic
Manticore version
Version: 0.3.3
Python version
Python 2.7.15+ Python 3.6.9
Dependencies
appdirs==1.4.3 attrdict==2.0.1 attrs==19.3.0 base58==1.0.3 black==19.10b0 capstone==4.0.1 certifi==2019.11.28 chardet==3.0.4 Click==7.0 crytic-compile==0.1.6 cytoolz==0.10.1 dataclasses==0.7 eth-abi==2.0.0 eth-account==0.4.0 eth-hash==0.2.0 eth-keyfile==0.5.1 eth-keys==0.2.4 eth-rlp==0.1.2 eth-typing==2.2.1 eth-utils==1.8.4 etheno==0.2.4 Flask==1.1.1 future==0.18.2 hexbytes==0.2.0 idna==2.8 importlib-metadata==1.1.0 ipfshttpclient==0.4.12 itsdangerous==1.1.0 Jinja2==2.10.3 jsonschema==3.2.0 lru-dict==1.1.6 manticore==0.3.3 MarkupSafe==1.1.1 more-itertools==8.0.0 multiaddr==0.0.8 mypy-extensions==0.4.3 netaddr==0.7.19 parsimonious==0.8.1 pathspec==0.6.0 ply==3.11 prettytable==0.7.2 protobuf==3.11.1 ptyprocess==0.6.0 pycryptodome==3.9.4 pyelftools==0.26 pyevmasm==0.2.1 pygobject==3.26.1 pyrsistent==0.15.6 pysha3==1.0.2 python-apt==1.6.4 PyYAML==5.3 regex==2019.11.1 requests==2.22.0 rlp==1.2.0 six==1.13.0 slither-analyzer==0.6.8 toml==0.10.0 toolz==0.10.0 typed-ast==1.4.0 unicorn==1.0.2rc1 urllib3==1.25.7 varint==1.0.2 wasm==1.2 web3==5.3.0 websockets==8.1 Werkzeug==0.16.0 wrapt==1.11.2 z3-solver==4.8.7.0 zipp==0.6.0
Summary of the problem
In a token example, I found that a transferred balance is different from a balance that I transfer. The token example is my_token.py whose source code is listed below.
Can you explain why I got this strange result?
==== my_token.py ============================
====================================
Step to reproduce the behavior
$ python3 my_token.py
Expected behavior
The transferred balance is equal to a balance that I transfer.
Actual behavior
The two balances are not equal as I explained in the summary.
Any relevant logs