@@ -6,6 +6,7 @@ use heimdall_vm::{
6
6
ext:: exec:: VMTrace ,
7
7
} ;
8
8
use petgraph:: { matrix_graph:: NodeIndex , Graph } ;
9
+ use std:: collections:: HashSet ;
9
10
10
11
/// convert a symbolic execution [`VMTrace`] into a [`Graph`] of blocks, illustrating the
11
12
/// control-flow graph found by the symbolic execution engine.
@@ -15,6 +16,7 @@ pub fn build_cfg(
15
16
contract_cfg : & mut Graph < String , String > ,
16
17
parent_node : Option < NodeIndex < u32 > > ,
17
18
jump_taken : bool ,
19
+ seen_nodes : & mut HashSet < String > ,
18
20
) -> Result < ( ) > {
19
21
let mut cfg_node: String = String :: new ( ) ;
20
22
let mut parent_node = parent_node;
@@ -23,9 +25,11 @@ pub fn build_cfg(
23
25
for operation in & vm_trace. operations {
24
26
let opcode_name = opcode_name ( operation. last_instruction . opcode ) ;
25
27
28
+ let opcode_offset = operation. last_instruction . instruction - 1 ; // start from 0x00
29
+
26
30
let assembly = format ! (
27
31
"{} {} {}" ,
28
- encode_hex_reduced( U256 :: from( operation . last_instruction . instruction - 1 ) ) , // start from 0x00
32
+ encode_hex_reduced( U256 :: from( opcode_offset ) ) ,
29
33
opcode_name,
30
34
if opcode_name. contains( "PUSH" ) {
31
35
encode_hex_reduced(
@@ -42,6 +46,12 @@ pub fn build_cfg(
42
46
43
47
cfg_node. push_str ( & format ! ( "{}\n " , & assembly) ) ;
44
48
}
49
+
50
+ // check if this node has been seen before
51
+ if seen_nodes. contains ( & cfg_node) {
52
+ return Ok ( ( ) ) ;
53
+ }
54
+ seen_nodes. insert ( cfg_node. clone ( ) ) ;
45
55
46
56
// add the node to the graph
47
57
let node_index = contract_cfg. add_node ( cfg_node) ;
@@ -63,6 +73,7 @@ pub fn build_cfg(
63
73
. last_instruction
64
74
. opcode ==
65
75
JUMPDEST ,
76
+ seen_nodes,
66
77
) ?;
67
78
}
68
79
0 commit comments