@@ -36,7 +36,7 @@ enum Value {
36
36
struct ValueByte {
37
37
data : Value ,
38
38
/// Byte of the data, 0 is most significant byte.
39
- byte : u32
39
+ byte : u32 ,
40
40
}
41
41
42
42
impl Display for Value {
@@ -82,8 +82,29 @@ impl Evaluator {
82
82
/// TODO should also set the current address.
83
83
pub fn new_transaction ( & mut self , calldata : Vec < u8 > ) {
84
84
self . calldata = Some ( calldata) ;
85
+ self . memory . clear ( ) ;
86
+ self . memory_slices . clear ( ) ;
85
87
self . unknown_memory_is_zero = true ;
86
88
}
89
+ /// Returns true if the evaluator can determine that the variable is equal
90
+ /// to the given literal value with the previously set restrictions.
91
+ pub fn variable_known_equal ( & self , var : & SMTVariable , value : & String ) -> bool {
92
+ if let Some ( Value :: Concrete ( v) ) = self . ssa_values . get ( & var. name ) {
93
+ if let Some ( lit) = literal_value ( value) {
94
+ return * v == lit;
95
+ }
96
+ }
97
+ false
98
+ }
99
+ pub fn variable_known_unequal ( & self , var : & SMTVariable , value : & String ) -> bool {
100
+ if let Some ( Value :: Concrete ( v) ) = self . ssa_values . get ( & var. name ) {
101
+ if let Some ( lit) = literal_value ( value) {
102
+ return * v != lit;
103
+ }
104
+ }
105
+ false
106
+ }
107
+
87
108
pub fn define_from_literal ( & mut self , var : & SMTVariable , literal : & Literal ) {
88
109
let value = & literal. literal ;
89
110
//println!("{} := {literal}", var.name);
@@ -113,37 +134,6 @@ impl Evaluator {
113
134
arguments : & Vec < SMTVariable > ,
114
135
return_vars : & [ SMTVariable ] ,
115
136
) {
116
- if builtin. name == "create" {
117
- println ! (
118
- "Create: {:?} {:?} {:?}" ,
119
- arguments[ 0 ] , arguments[ 1 ] , arguments[ 2 ]
120
- ) ;
121
-
122
- // self.ssa_values
123
- // .insert(return_vars[0].name.clone(), BigUint::from(1234u64));
124
- }
125
- // if builtin.name == "sstore" {
126
- // if let (Some(key), Some(value)) = (
127
- // self.ssa_values.get(&arguments[0].name).cloned(),
128
- // self.ssa_values.get(&arguments[1].name).cloned(),
129
- // ) {
130
- // self.storage.insert(key, value);
131
- // }
132
- // }
133
- // if builtin.name == "sload" {
134
- // if let Some(key) = self.ssa_values.get(&arguments[0].name).cloned() {
135
- // if let Some(value) = self.storage.get(&key).cloned() {
136
- // self.ssa_values.insert(return_vars[0].name.clone(), value);
137
- // } else {
138
- // // TODO assume unknown storage is some weird value - should use unknown bits later
139
- // self.ssa_values.insert(
140
- // return_vars[0].name.clone(),
141
- // BigUint::from(0x1234567812345678u64),
142
- // );
143
- // }
144
- // }
145
- // }
146
-
147
137
let mask = ( BigUint :: from ( 1u64 ) << 256 ) - BigUint :: from ( 1u64 ) ;
148
138
let two256 = BigUint :: from ( 1u64 ) << 256 ;
149
139
let address_mask = ( BigUint :: from ( 1u64 ) << 160 ) - BigUint :: from ( 1u64 ) ;
@@ -200,6 +190,18 @@ impl Evaluator {
200
190
self . memory_slices . insert ( addr. clone ( ) , Value :: DataRef ( offset. clone ( ) ) ) ;
201
191
None
202
192
}
193
+ ( "calldatasize" , [ ] ) => {
194
+ self . calldata . as_ref ( ) . map ( |cd| Value :: Concrete ( BigUint :: from ( cd. len ( ) ) ) )
195
+ }
196
+ ( "calldataload" , [ Some ( Value :: Concrete ( addr) ) ] ) => {
197
+ self . calldata . as_ref ( ) . map ( |cd| {
198
+ let mut result = vec ! [ 0u8 ; 32 ] ;
199
+ for i in 0 ..32usize {
200
+ result[ i] = cd. get ( addr. to_usize ( ) . unwrap ( ) + i) . copied ( ) . unwrap_or_default ( ) ;
201
+ }
202
+ Value :: Concrete ( BigUint :: from_bytes_be ( & result) )
203
+ } )
204
+ }
203
205
( "create" , [ _ether_value, Some ( Value :: Concrete ( offset) ) , _size /* TODO check size */ ] ) => {
204
206
if let Some ( Value :: DataRef ( name) ) = self . memory_slices . get ( offset) {
205
207
Some ( Value :: KnownContractAddress ( name. clone ( ) , 0 ) ) // TODO increment coutner
@@ -233,14 +235,17 @@ impl Evaluator {
233
235
self . ssa_values . insert ( return_vars[ 0 ] . name . clone ( ) , result) ;
234
236
}
235
237
if builtin. name == "call" {
236
- for i in 0x80 ..0xc4 {
237
- println ! ( "{:x}: {:x?}" , i, self . read_memory_byte( & BigUint :: from( i as u32 ) ) ) ;
238
- }
238
+ // for i in 0x80..0xc4 {
239
+ // println!(
240
+ // "{:x}: {:x?}",
241
+ // i,
242
+ // self.read_memory_byte(&BigUint::from(i as u32))
243
+ // );
244
+ // }
239
245
// if let (Some(Value::Concrete(in_offset)), Some(Value::Concrete(in_len))) = (&arg_values[3], &arg_values[4]) {
240
246
// println!("{:x?}", &self.get_memory_slice(in_offset.clone(), in_len.clone()).unwrap());
241
247
242
248
// }
243
-
244
249
}
245
250
match builtin. name {
246
251
"create" | "sstore" | "sload" | "call" | "datacopy" | "mstore" => {
@@ -294,8 +299,17 @@ impl Evaluator {
294
299
295
300
fn read_memory ( & self , offset : & BigUint ) -> Option < Value > {
296
301
let candidate = self . memory . get ( offset) ;
297
- if let Some ( ValueByte { data : candidate, ..} ) = candidate {
298
- if ( 0 ..32u32 ) . all ( |i| self . memory . get ( & ( offset. clone ( ) + BigUint :: from ( i) ) ) == Some ( & ValueByte { data : candidate. clone ( ) , byte : i} ) ) {
302
+ if let Some ( ValueByte {
303
+ data : candidate, ..
304
+ } ) = candidate
305
+ {
306
+ if ( 0 ..32u32 ) . all ( |i| {
307
+ self . memory . get ( & ( offset. clone ( ) + BigUint :: from ( i) ) )
308
+ == Some ( & ValueByte {
309
+ data : candidate. clone ( ) ,
310
+ byte : i,
311
+ } )
312
+ } ) {
299
313
return Some ( candidate. clone ( ) ) ;
300
314
}
301
315
}
@@ -313,18 +327,30 @@ impl Evaluator {
313
327
314
328
fn read_memory_byte ( & self , offset : & BigUint ) -> Option < u8 > {
315
329
match self . memory . get ( offset) {
316
- Some ( ValueByte { data : Value :: Concrete ( v) , byte : i} ) => {
317
- Some ( v. to_bytes_le ( ) . get ( ( 31 - i) as usize ) . copied ( ) . unwrap_or_default ( ) )
318
- }
319
- _ => None
330
+ Some ( ValueByte {
331
+ data : Value :: Concrete ( v) ,
332
+ byte : i,
333
+ } ) => Some (
334
+ v. to_bytes_le ( )
335
+ . get ( ( 31 - i) as usize )
336
+ . copied ( )
337
+ . unwrap_or_default ( ) ,
338
+ ) ,
339
+ _ => None ,
320
340
}
321
341
}
322
342
323
343
fn write_memory ( & mut self , offset : BigUint , value : Option < Value > ) {
324
344
match value {
325
345
Some ( value) => {
326
346
for i in 0 ..32u32 {
327
- self . memory . insert ( offset. clone ( ) + BigUint :: from ( i) , ValueByte { data : value. clone ( ) , byte : i} ) ;
347
+ self . memory . insert (
348
+ offset. clone ( ) + BigUint :: from ( i) ,
349
+ ValueByte {
350
+ data : value. clone ( ) ,
351
+ byte : i,
352
+ } ,
353
+ ) ;
328
354
}
329
355
}
330
356
None => {
@@ -337,16 +363,16 @@ impl Evaluator {
337
363
338
364
fn get_memory_slice ( & self , offset : BigUint , len : BigUint ) -> Option < Vec < u8 > > {
339
365
// TODO aliasing?
340
- ( 0 ..( len. to_u64 ( ) . unwrap ( ) ) ) . map ( |i| {
341
- self . read_memory_byte ( & ( offset. clone ( ) + BigUint :: from ( i) ) )
342
- } ) . fold ( Some ( Vec :: < u8 > :: new ( ) ) , |acc, v| {
343
- if let ( Some ( mut acc) , Some ( v) ) = ( acc, v) {
344
- acc. push ( v) ;
345
- Some ( acc)
346
- } else {
347
- None
348
- }
349
- } )
366
+ ( 0 ..( len. to_u64 ( ) . unwrap ( ) ) )
367
+ . map ( |i| self . read_memory_byte ( & ( offset. clone ( ) + BigUint :: from ( i) ) ) )
368
+ . fold ( Some ( Vec :: < u8 > :: new ( ) ) , |acc, v| {
369
+ if let ( Some ( mut acc) , Some ( v) ) = ( acc, v) {
370
+ acc. push ( v) ;
371
+ Some ( acc)
372
+ } else {
373
+ None
374
+ }
375
+ } )
350
376
}
351
377
}
352
378
@@ -355,3 +381,13 @@ fn wrap(mut x: BigUint) -> BigUint {
355
381
// TODO optimization: work directly on limbs
356
382
x & mask
357
383
}
384
+
385
+ fn literal_value ( value : & String ) -> Option < BigUint > {
386
+ if let Some ( hex) = value. strip_prefix ( "0x" ) {
387
+ Some ( BigUint :: from_str_radix ( hex, 16 ) . unwrap ( ) )
388
+ } else if matches ! ( value. chars( ) . next( ) . unwrap( ) , '0' ..='9' ) {
389
+ Some ( BigUint :: from_str_radix ( value, 10 ) . unwrap ( ) )
390
+ } else {
391
+ None
392
+ }
393
+ }
0 commit comments