@@ -43,12 +43,16 @@ impl WasmReader<'_> {
4343
4444 /// Parses a variable-length `u64` (can be casted to a smaller uint if the result fits)
4545 /// Taken from <https://github.com/bytecodealliance/wasm-tools>
46+ #[ allow( unused) ]
4647 pub fn read_var_u64 ( & mut self ) -> Result < u64 > {
4748 let mut result = 0 ;
4849 let mut shift = 0 ;
4950
5051 loop {
5152 let mut byte = self . read_u8 ( ) ?;
53+ // maximum allowed num of leb bytes for u32 is ceil(32.0/7.0) == 10
54+ // shift >= 63 checks we're at the 10th bit or larger
55+ // byte != 1 checks whether (this byte lost bits when shifted) or (the continuation bit is set)
5256 if shift == 63 && byte != 0 && byte != 1 {
5357 while byte & Self :: CONTINUATION_BIT != 0 {
5458 byte = self . read_u8 ( ) ?;
@@ -70,9 +74,25 @@ impl WasmReader<'_> {
7074 /// Parses a variable-length `u32` as specified by [LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128).
7175 /// Note: If `Err`, the [WasmReader] object is no longer guaranteed to be in a valid state
7276 pub fn read_var_u32 ( & mut self ) -> Result < u32 > {
73- Self :: read_var_u64 ( self ) ?
74- . try_into ( )
75- . map_err ( |_| Error :: Overflow )
77+ let mut result: u32 = 0 ;
78+ let mut shift = 0 ;
79+
80+ loop {
81+ let byte = self . read_u8 ( ) ?;
82+ result |= ( ( byte & 0x7F ) as u32 ) << shift;
83+ // maximum allowed num of leb bytes for u32 is ceil(32.0/7.0) == 5
84+ // shift >= 28 checks we're at the 5th bit or larger
85+ // byte >> 32-28 checks whether (this byte lost bits when shifted) or (the continuation bit is set)
86+ if shift >= 28 && byte >> ( 32 - shift) != 0 {
87+ return Err ( Error :: Overflow ) ;
88+ }
89+
90+ if byte & Self :: CONTINUATION_BIT == 0 {
91+ return Ok ( result) ;
92+ }
93+
94+ shift += 7 ;
95+ }
7696 }
7797
7898 pub fn read_var_f64 ( & mut self ) -> Result < u64 > {
@@ -81,46 +101,74 @@ impl WasmReader<'_> {
81101 Ok ( word)
82102 }
83103
104+ /// Adapted from <https://github.com/bytecodealliance/wasm-tools>
84105 pub fn read_var_i32 ( & mut self ) -> Result < i32 > {
85106 let mut result: i32 = 0 ;
86107 let mut shift: u32 = 0 ;
87108
88- let mut byte: i32 ;
89109 loop {
90- byte = self . read_u8 ( ) ? as i32 ;
91- result |= ( byte & 0b01111111 ) << shift;
110+ let byte = self . read_u8 ( ) ?;
111+ result |= ( ( byte & 0x7F ) as i32 ) << shift;
112+
113+ if shift >= 28 {
114+ // maximum allowed num of leb bytes for u32 is ceil(32.0/7.0) == 5
115+ // shift >= 28 checks we're at the 5th bit or larger
116+ let there_are_more_bytes = ( byte & Self :: CONTINUATION_BIT ) != 0 ;
117+ let ashifted_unused_bits = ( byte << 1 ) as i8 >> ( 32 - shift) ;
118+ // the top unused bits of 35 bytes should be either 111 for negative numbers or 000 for positive numbers
119+ // therefore ashifted_unused_bits should be -1 or 0
120+ if there_are_more_bytes || ( ashifted_unused_bits != 0 && ashifted_unused_bits != -1 )
121+ {
122+ return Err ( Error :: Overflow ) ;
123+ } else {
124+ // no need to ashift unfilled bits, all 32 bits are filled
125+ return Ok ( result) ;
126+ }
127+ }
128+
92129 shift += 7 ;
130+
93131 if ( byte & 0b10000000 ) == 0 {
94132 break ;
95133 }
96134 }
97135
98- if ( shift < mem:: size_of :: < i32 > ( ) as u32 * 8 ) && ( byte & 0x40 != 0 ) {
99- result |= !0 << shift;
100- }
101-
102- Ok ( result)
136+ // fill in unfilled bits with sign bit
137+ let ashift = mem:: size_of :: < i32 > ( ) * 8 - shift as usize ;
138+ Ok ( ( result << ashift) >> ashift)
103139 }
104140
105141 pub fn read_var_i33 ( & mut self ) -> Result < i64 > {
106142 let mut result: i64 = 0 ;
107- let mut shift: u64 = 0 ;
143+ let mut shift: u32 = 0 ;
108144
109- let mut byte: i64 ;
110145 loop {
111- byte = self . read_u8 ( ) ? as i64 ;
112- result |= ( byte & 0b0111_1111 ) << shift;
146+ let byte = self . read_u8 ( ) ?;
147+ result |= ( ( byte & 0x7F ) as i64 ) << shift;
148+
149+ if shift >= 28 {
150+ // maximum allowed num of leb bytes for i33 is ceil(33.0/7.0) == 5
151+ // shift >= 28 checks we're at the 5th bit or larger
152+ let there_are_more_bytes = ( byte & Self :: CONTINUATION_BIT ) != 0 ;
153+ let ashifted_unused_bits = ( byte << 1 ) as i8 >> ( 33 - shift) ;
154+ // the top unused bits of 35 bytes should be either 11 for negative numbers or 00 for positive numbers
155+ // therefore ashifted_unused_bits should be -1 or 0
156+ if there_are_more_bytes || ( ashifted_unused_bits != 0 && ashifted_unused_bits != -1 )
157+ {
158+ return Err ( Error :: Overflow ) ;
159+ }
160+ }
161+
113162 shift += 7 ;
114- if ( byte & 0b1000_0000 ) == 0 {
163+
164+ if ( byte & 0b10000000 ) == 0 {
115165 break ;
116166 }
117167 }
118168
119- if shift < 33 && ( byte & 0x40 != 0 ) {
120- result |= !0 << shift;
121- }
122-
123- Ok ( result)
169+ // fill in unfilled bits with sign bit
170+ let ashift = mem:: size_of :: < i64 > ( ) * 8 - shift as usize ;
171+ Ok ( ( result << ashift) >> ashift)
124172 }
125173
126174 pub fn read_var_f32 ( & mut self ) -> Result < u32 > {
@@ -141,23 +189,38 @@ impl WasmReader<'_> {
141189
142190 pub fn read_var_i64 ( & mut self ) -> Result < i64 > {
143191 let mut result: i64 = 0 ;
144- let mut shift: u64 = 0 ;
192+ let mut shift: u32 = 0 ;
145193
146- let mut byte: i64 ;
147194 loop {
148- byte = self . read_u8 ( ) ? as i64 ;
149- result |= ( byte & 0b0111_1111 ) << shift;
195+ let byte = self . read_u8 ( ) ?;
196+ result |= ( ( byte & 0x7F ) as i64 ) << shift;
197+
198+ if shift >= 63 {
199+ // maximum allowed num of leb bytes for i33 is ceil(64.0/7.0) == 10
200+ // shift >= 63 checks we're at the 10th bit or larger
201+ let there_are_more_bytes = ( byte & Self :: CONTINUATION_BIT ) != 0 ;
202+ let ashifted_unused_bits = ( byte << 1 ) as i8 >> ( 64 - shift) ;
203+ // the top unused bits of 70 bytes should be either 111111 for negative numbers or 000000 for positive numbers
204+ // therefore ashifted_unused_bits should be -1 or 0
205+ if there_are_more_bytes || ( ashifted_unused_bits != 0 && ashifted_unused_bits != -1 )
206+ {
207+ return Err ( Error :: Overflow ) ;
208+ } else {
209+ // no need to ashift unfilled bits, all 64 bits are filled
210+ return Ok ( result) ;
211+ }
212+ }
213+
150214 shift += 7 ;
151- if ( byte & 0b1000_0000 ) == 0 {
215+
216+ if ( byte & 0b10000000 ) == 0 {
152217 break ;
153218 }
154219 }
155220
156- if shift < 64 && ( byte & 0x40 != 0 ) {
157- result |= !0 << shift;
158- }
159-
160- Ok ( result)
221+ // fill in unfilled bits with sign bit
222+ let ashift = mem:: size_of :: < i64 > ( ) * 8 - shift as usize ;
223+ Ok ( ( result << ashift) >> ashift)
161224 }
162225
163226 /// Note: If `Err`, the [WasmReader] object is no longer guaranteed to be in a valid state
0 commit comments