1
- use revm_primitives:: { eof:: EofDecodeError , HashSet } ;
2
-
3
1
use crate :: {
4
2
instructions:: utility:: { read_i16, read_u16} ,
5
3
opcode,
6
4
primitives:: {
7
5
bitvec:: prelude:: { bitvec, BitVec , Lsb0 } ,
8
- eof:: TypesSection ,
6
+ eof:: { EofDecodeError , TypesSection } ,
9
7
legacy:: JumpTable ,
10
- Bytecode , Bytes , Eof , LegacyAnalyzedBytecode ,
8
+ Bytecode , Bytes , Eof , HashSet , LegacyAnalyzedBytecode ,
11
9
} ,
12
10
OPCODE_INFO_JUMPTABLE , STACK_LIMIT ,
13
11
} ;
14
- use std:: { sync:: Arc , vec, vec:: Vec } ;
12
+ use core:: convert:: identity;
13
+ use std:: { borrow:: Cow , sync:: Arc , vec, vec:: Vec } ;
15
14
16
15
const EOF_NON_RETURNING_FUNCTION : u8 = 0x80 ;
17
16
@@ -66,33 +65,36 @@ fn analyze(code: &[u8]) -> JumpTable {
66
65
JumpTable ( Arc :: new ( jumps) )
67
66
}
68
67
69
- pub fn validate_raw_eof ( bytecode : Bytes ) -> Result < Eof , EofError > {
70
- let eof = Eof :: decode ( bytecode) ?;
68
+ /// Decodes `raw` into an [`Eof`] container and validates it.
69
+ pub fn validate_raw_eof ( raw : Bytes ) -> Result < Eof , EofError > {
70
+ let eof = Eof :: decode ( raw) ?;
71
71
validate_eof ( & eof) ?;
72
72
Ok ( eof)
73
73
}
74
74
75
- /// Validate Eof structures .
75
+ /// Fully validates an [` Eof`] container .
76
76
pub fn validate_eof ( eof : & Eof ) -> Result < ( ) , EofError > {
77
- // clone is cheap as it is Bytes and a header.
78
- let mut queue = vec ! [ eof. clone( ) ] ;
77
+ if eof. body . container_section . is_empty ( ) {
78
+ validate_eof_codes ( eof) ?;
79
+ return Ok ( ( ) ) ;
80
+ }
79
81
80
- while let Some ( eof) = queue. pop ( ) {
81
- // iterate over types
82
+ let mut stack = Vec :: with_capacity ( 4 ) ;
83
+ stack. push ( Cow :: Borrowed ( eof) ) ;
84
+ while let Some ( eof) = stack. pop ( ) {
85
+ // Validate the current container.
82
86
validate_eof_codes ( & eof) ?;
83
- // iterate over containers, convert them to Eof and add to analyze_eof
84
- for container in eof. body . container_section {
85
- queue . push ( Eof :: decode ( container) ? ) ;
87
+ // Decode subcontainers and push them to the stack.
88
+ for container in & eof. body . container_section {
89
+ stack . push ( Cow :: Owned ( Eof :: decode ( container. clone ( ) ) ? ) ) ;
86
90
}
87
91
}
88
92
89
- // Eof is valid
90
93
Ok ( ( ) )
91
94
}
92
95
93
- /// Validate EOF
96
+ /// Validates an [`Eof`] structure, without recursing into containers.
94
97
pub fn validate_eof_codes ( eof : & Eof ) -> Result < ( ) , EofValidationError > {
95
- let mut queued_codes = vec ! [ false ; eof. body. code_section. len( ) ] ;
96
98
if eof. body . code_section . len ( ) != eof. body . types_section . len ( ) {
97
99
return Err ( EofValidationError :: InvalidTypesSection ) ;
98
100
}
@@ -101,8 +103,6 @@ pub fn validate_eof_codes(eof: &Eof) -> Result<(), EofValidationError> {
101
103
// no code sections. This should be already checked in decode.
102
104
return Err ( EofValidationError :: NoCodeSections ) ;
103
105
}
104
- // first section is default one.
105
- queued_codes[ 0 ] = true ;
106
106
107
107
// the first code section must have a type signature
108
108
// (0, 0x80, max_stack_height) (0 inputs non-returning function)
@@ -111,11 +111,16 @@ pub fn validate_eof_codes(eof: &Eof) -> Result<(), EofValidationError> {
111
111
return Err ( EofValidationError :: InvalidTypesSection ) ;
112
112
}
113
113
114
+ // first section is default one.
115
+ let mut code_sections_accessed = vec ! [ false ; eof. body. code_section. len( ) ] ;
116
+ code_sections_accessed[ 0 ] = true ;
117
+
114
118
// start validation from code section 0.
115
- let mut queue = vec ! [ 0 ] ;
116
- while let Some ( index) = queue. pop ( ) {
119
+ let mut stack = Vec :: with_capacity ( 16 ) ;
120
+ stack. push ( 0 ) ;
121
+ while let Some ( index) = stack. pop ( ) {
117
122
let code = & eof. body . code_section [ index] ;
118
- let accessed_codes = validate_eof_code (
123
+ let accessed = validate_eof_code (
119
124
code,
120
125
eof. header . data_size as usize ,
121
126
index,
@@ -124,15 +129,15 @@ pub fn validate_eof_codes(eof: &Eof) -> Result<(), EofValidationError> {
124
129
) ?;
125
130
126
131
// queue accessed codes.
127
- accessed_codes . into_iter ( ) . for_each ( |i| {
128
- if !queued_codes [ i] {
129
- queued_codes [ i] = true ;
130
- queue . push ( i) ;
132
+ accessed . into_iter ( ) . for_each ( |i| {
133
+ if !code_sections_accessed [ i] {
134
+ code_sections_accessed [ i] = true ;
135
+ stack . push ( i) ;
131
136
}
132
137
} ) ;
133
138
}
134
139
// iterate over accessed codes and check if all are accessed.
135
- if queued_codes . into_iter ( ) . any ( |x| !x ) {
140
+ if !code_sections_accessed . into_iter ( ) . all ( identity ) {
136
141
return Err ( EofValidationError :: CodeSectionNotAccessed ) ;
137
142
}
138
143
0 commit comments