@@ -749,6 +749,7 @@ def extend_with_zeroes(b):
749
749
# Used calldata size
750
750
self ._used_calldata_size = 0
751
751
self ._valid_jmpdests = set ()
752
+ self ._sha3 = {}
752
753
753
754
@property
754
755
def pc (self ):
@@ -777,6 +778,7 @@ def gas(self):
777
778
778
779
def __getstate__ (self ):
779
780
state = super ().__getstate__ ()
781
+ state ["sha3" ] = self ._sha3
780
782
state ["memory" ] = self .memory
781
783
state ["world" ] = self ._world
782
784
state ["constraints" ] = self .constraints
@@ -800,6 +802,7 @@ def __getstate__(self):
800
802
return state
801
803
802
804
def __setstate__ (self , state ):
805
+ self ._sha3 = state ["sha3" ]
803
806
self ._checkpoint_data = state ["_checkpoint_data" ]
804
807
self ._published_pre_instruction_events = state ["_published_pre_instruction_events" ]
805
808
self ._on_transaction = state ["_on_transaction" ]
@@ -940,6 +943,7 @@ def _push(self, value):
940
943
value = simplify (value )
941
944
if isinstance (value , Constant ) and not value .taint :
942
945
value = value .value
946
+
943
947
self .stack .append (value )
944
948
945
949
def _top (self , n = 0 ):
@@ -1065,9 +1069,6 @@ def _pop_arguments(self):
1065
1069
for _ in range (current .pops ):
1066
1070
arguments .append (self ._pop ())
1067
1071
# simplify stack arguments
1068
- for i , arg in enumerate (arguments ):
1069
- if isinstance (arg , Constant ) and not arg .taint :
1070
- arguments [i ] = arg .value
1071
1072
return arguments
1072
1073
1073
1074
def _top_arguments (self ):
@@ -1119,7 +1120,7 @@ def _checkpoint(self):
1119
1120
if self ._checkpoint_data is None :
1120
1121
if not self ._published_pre_instruction_events :
1121
1122
self ._published_pre_instruction_events = True
1122
- self ._publish ("will_decode_instruction" , self .pc )
1123
+ # self._publish("will_decode_instruction", self.pc)
1123
1124
self ._publish (
1124
1125
"will_evm_execute_instruction" , self .instruction , self ._top_arguments ()
1125
1126
)
@@ -1154,7 +1155,7 @@ def _set_check_jmpdest(self, flag=True):
1154
1155
Note that at this point `flag` can be the conditional from a JUMPI
1155
1156
instruction hence potentially a symbolic value.
1156
1157
"""
1157
- self ._check_jumpdest = simplify ( flag )
1158
+ self ._check_jumpdest = flag
1158
1159
1159
1160
def _check_jmpdest (self ):
1160
1161
"""
@@ -1164,7 +1165,13 @@ def _check_jmpdest(self):
1164
1165
Here, if symbolic, the conditional `self._check_jumpdest` would be
1165
1166
already constrained to a single concrete value.
1166
1167
"""
1167
- should_check_jumpdest = self ._check_jumpdest
1168
+ # If pc is already pointing to a JUMPDEST thre is no need to check.
1169
+ pc = self .pc .value if isinstance (self .pc , Constant ) else self .pc
1170
+ if pc in self ._valid_jumpdests :
1171
+ self ._check_jumpdest = False
1172
+ return
1173
+
1174
+ should_check_jumpdest = simplify (self ._check_jumpdest )
1168
1175
if isinstance (should_check_jumpdest , Constant ):
1169
1176
should_check_jumpdest = should_check_jumpdest .value
1170
1177
elif issymbolic (should_check_jumpdest ):
@@ -1176,11 +1183,10 @@ def _check_jmpdest(self):
1176
1183
should_check_jumpdest = should_check_jumpdest_solutions [0 ]
1177
1184
1178
1185
# If it can be solved only to False just set it False. If it can be solved
1179
- # only to True, process it and also se it to False
1186
+ # only to True, process it and also set it to False
1180
1187
self ._check_jumpdest = False
1181
1188
1182
1189
if should_check_jumpdest :
1183
- pc = self .pc .value if isinstance (self .pc , Constant ) else self .pc
1184
1190
if pc not in self ._valid_jumpdests :
1185
1191
raise InvalidOpcode ()
1186
1192
@@ -1235,7 +1241,6 @@ def setstate(state, value):
1235
1241
last_pc , last_gas , instruction , arguments , fee , allocated = self ._checkpoint ()
1236
1242
result = self ._handler (* arguments )
1237
1243
self ._advance (result )
1238
-
1239
1244
except ConcretizeGas as ex :
1240
1245
1241
1246
def setstate (state , value ):
@@ -1324,19 +1329,13 @@ def _load(self, offset, size=1):
1324
1329
except Exception :
1325
1330
pass
1326
1331
1327
- for i in range (size ):
1328
- self ._publish (
1329
- "did_evm_read_memory" , offset + i , Operators .EXTRACT (value , (size - i - 1 ) * 8 , 8 )
1330
- )
1332
+ self ._publish ("did_evm_read_memory" , offset , value , size )
1331
1333
return value
1332
1334
1333
1335
def _store (self , offset , value , size = 1 ):
1334
1336
"""Stores value in memory as a big endian"""
1335
1337
self .memory .write_BE (offset , value , size )
1336
- for i in range (size ):
1337
- self ._publish (
1338
- "did_evm_write_memory" , offset + i , Operators .EXTRACT (value , (size - i - 1 ) * 8 , 8 )
1339
- )
1338
+ self ._publish ("did_evm_write_memory" , offset , value , size )
1340
1339
1341
1340
def safe_add (self , a , b , * args ):
1342
1341
a = Operators .ZEXTEND (a , 512 )
@@ -1575,7 +1574,24 @@ def SHA3(self, start, size):
1575
1574
1576
1575
"""
1577
1576
data = self .read_buffer (start , size )
1578
- return self .world .symbolic_function (globalsha3 , data )
1577
+
1578
+ if consts .sha3 == consts .sha3 .fake :
1579
+ # Fake hash selected. Replace with symbol friendly hash.
1580
+ h = len (data ) + 0x4141414141414141414141414141414141414141414141414141414141414100
1581
+ for i in range (0 , len (data ), 32 ):
1582
+ h <<= 16
1583
+ h += data .read_BE (i , 32 )
1584
+
1585
+ # Try to avoid some common incorrect cases
1586
+ self .constraints .add (h != 0 )
1587
+ # Force fake collision resistance
1588
+ for x , y in self ._sha3 .items ():
1589
+ self .constraints .add ((data == x ) == (h == y ))
1590
+
1591
+ self ._sha3 [data ] = h
1592
+ return h
1593
+ else :
1594
+ return self .world .symbolic_function (globalsha3 , data )
1579
1595
1580
1596
############################################################################
1581
1597
# Environmental Information
@@ -1646,7 +1662,7 @@ def CALLDATACOPY_gas(self, mem_offset, data_offset, size):
1646
1662
memfee = self ._get_memfee (mem_offset , size )
1647
1663
return self .safe_add (copyfee , memfee )
1648
1664
1649
- # @concretized_args(size="SAMPLED ")
1665
+ # @concretized_args(size="ALL ")
1650
1666
def CALLDATACOPY (self , mem_offset , data_offset , size ):
1651
1667
"""Copy input data in current environment to memory"""
1652
1668
# calldata_overflow = const.calldata_overflow
@@ -1680,10 +1696,6 @@ def CALLDATACOPY(self, mem_offset, data_offset, size):
1680
1696
logger .info (f"Constraining CALLDATACOPY size to { cap } " )
1681
1697
max_size = cap
1682
1698
self .constraints .add (Operators .ULE (size , cap ))
1683
- # cond = Operators.OR(size == 0, size==4)
1684
- # for conc_size in range(8,max_size, 32):
1685
- # cond = Operators.OR(size==conc_size, cond)
1686
- # self.constraints.add(cond)
1687
1699
1688
1700
for i in range (max_size ):
1689
1701
try :
0 commit comments