wasm/core/decoding/
values.rs

1//! Methods to read basic WASM Values from a [WasmDecoder] object.
2//!
3//! See: <https://webassembly.github.io/spec/core/binary/values.html>
4//!
5//! Note: If any of these methods return `Err`, they may have consumed some bytes from the [WasmDecoder] object and thus consequent calls may result in unexpected behaviour.
6//! This is due to the fact that these methods read elemental types which cannot be split.
7
8use alloc::vec::Vec;
9
10use crate::{
11    core::{decoding::reader::WasmDecoder, utils::ToUsizeExt},
12    DecodingError,
13};
14
15/// Wasm encodes integers according to the LEB128 format, which specifies that
16/// only 7 bits of every byte are used to store the integer's bits. The 8th bit
17/// is always used as a bitflag for whether the next byte shall also be read as
18/// part of the current integer. Therefore, it can be called a continuation bit,
19/// which is stored here as a global constant to improve code readability.
20const CONTINUATION_BIT: u8 = 0b10000000;
21
22const INTEGER_BIT_FLAG: u8 = !CONTINUATION_BIT;
23
24impl<'wasm> WasmDecoder<'wasm> {
25    /// Tries to read one byte and fails if the end of file is reached.
26    pub fn decode_u8(&mut self) -> Result<u8, DecodingError> {
27        let byte = self.peek_u8()?;
28        self.pc += 1;
29        Ok(byte)
30    }
31
32    /// Parses a variable-length `u32` as specified by [LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128).
33    /// Note: If `Err`, the [WasmDecoder] object is no longer guaranteed to be in a valid state
34    pub fn decode_var_u32(&mut self) -> Result<u32, DecodingError> {
35        /// Because up to 5 bytes (each storing 7 bits) may be used to store 32 bits,
36        /// some bits in the last byte will be left unused. This is a bitmask for
37        /// exactly these bits in the last byte.
38        const PADDING_IN_LAST_BYTE_BIT_MASK: u8 = 0b01110000;
39
40        let mut result: u32 = 0;
41
42        let byte = self.decode_u8()?;
43        result |= u32::from(byte & INTEGER_BIT_FLAG);
44        if byte & CONTINUATION_BIT == 0 {
45            return Ok(result);
46        }
47
48        let byte = self.decode_u8()?;
49        result |= u32::from(byte & INTEGER_BIT_FLAG) << 7;
50        if byte & CONTINUATION_BIT == 0 {
51            return Ok(result);
52        }
53
54        let byte = self.decode_u8()?;
55        result |= u32::from(byte & INTEGER_BIT_FLAG) << 14;
56        if byte & CONTINUATION_BIT == 0 {
57            return Ok(result);
58        }
59
60        let byte = self.decode_u8()?;
61        result |= u32::from(byte & INTEGER_BIT_FLAG) << 21;
62        if byte & CONTINUATION_BIT == 0 {
63            return Ok(result);
64        }
65
66        let byte = self.decode_u8()?;
67        result |= u32::from(byte & INTEGER_BIT_FLAG) << 28;
68
69        // there can only be a maximum number of 5 bytes for a 32-bit integer
70        let has_next_byte = byte & CONTINUATION_BIT > 0;
71        let padding_bits_are_not_zero = byte & PADDING_IN_LAST_BYTE_BIT_MASK > 0;
72        if has_next_byte || padding_bits_are_not_zero {
73            // TODO distinguish between both error variants
74            return Err(DecodingError::MalformedVariableLengthInteger);
75        }
76
77        Ok(result)
78    }
79
80    pub fn decode_f64(&mut self) -> Result<u64, DecodingError> {
81        let bytes = self.strip_bytes::<8>()?;
82        Ok(u64::from_le_bytes(bytes))
83    }
84
85    pub fn decode_var_i32(&mut self) -> Result<i32, DecodingError> {
86        /// Because up to 5 bytes (each storing 7 bits) may be used to store 32 bits,
87        /// some bits in the last byte will be left unused. This is a bitmask for
88        /// exactly these bits in the last byte.
89        const PADDING_IN_LAST_BYTE_BITMASK: u8 = 0b01110000;
90
91        /// This bitflag defines the position of the sign bit in the last byte.
92        const SIGN_IN_LAST_BYTE_BITFLAG: u8 = 0b00001000;
93
94        /// Number of bits in this number type
95        const NUM_BITS: u32 = 32;
96
97        let mut result: i32 = 0;
98
99        let byte = self.decode_u8()?;
100        result |= i32::from(byte & INTEGER_BIT_FLAG);
101        if byte & CONTINUATION_BIT == 0 {
102            /// before returning the result, we need to sign extend the unspecified bits
103            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 7;
104            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
105            return Ok(sign_extended_result);
106        }
107
108        let byte = self.decode_u8()?;
109        result |= i32::from(byte & INTEGER_BIT_FLAG) << 7;
110        if byte & CONTINUATION_BIT == 0 {
111            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 14;
112            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
113            return Ok(sign_extended_result);
114        }
115
116        let byte = self.decode_u8()?;
117        result |= i32::from(byte & INTEGER_BIT_FLAG) << 14;
118        if byte & CONTINUATION_BIT == 0 {
119            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 21;
120            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
121            return Ok(sign_extended_result);
122        }
123
124        let byte = self.decode_u8()?;
125        result |= i32::from(byte & INTEGER_BIT_FLAG) << 21;
126        if byte & CONTINUATION_BIT == 0 {
127            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 28;
128            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
129            return Ok(sign_extended_result);
130        }
131
132        let byte = self.decode_u8()?;
133        result |= i32::from(byte & INTEGER_BIT_FLAG) << 28;
134
135        // there can only be a maximum number of 5 bytes for a 32-bit integer
136        let has_next_byte = byte & CONTINUATION_BIT > 0;
137        if has_next_byte {
138            // TODO distinguish between both error variants
139            return Err(DecodingError::MalformedVariableLengthInteger);
140        }
141
142        // Verify that the padding and sign bits are either all ones or all
143        // zeros. To do this we count the ones and check if that number is zero
144        // or equal to the number of ones in both bitmasks combined.
145        const PADDING_AND_SIGN_BITMASK: u8 =
146            PADDING_IN_LAST_BYTE_BITMASK | SIGN_IN_LAST_BYTE_BITFLAG;
147        let number_of_ones_in_padding_and_sign_bits =
148            (byte & PADDING_AND_SIGN_BITMASK).count_ones();
149        let padding_bits_match_sign_bit = number_of_ones_in_padding_and_sign_bits
150            == PADDING_AND_SIGN_BITMASK.count_ones()
151            || number_of_ones_in_padding_and_sign_bits == 0;
152        if !padding_bits_match_sign_bit {
153            // TODO distinguish between both error variants
154            return Err(DecodingError::MalformedVariableLengthInteger);
155        }
156
157        Ok(result)
158    }
159
160    pub fn decode_var_i33_as_u32(&mut self) -> Result<u32, DecodingError> {
161        /// Because up to 5 bytes (each storing 7 bits) may be used to store 32 bits,
162        /// some bits in the last byte will be left unused. This is a bitmask for
163        /// exactly these bits in the last byte.
164        const PADDING_IN_LAST_BYTE_BITMASK: u8 = 0b01100000;
165
166        /// This bitflag defines the position of the sign bit in the last byte.
167        const SIGN_IN_LAST_BYTE_BITFLAG: u8 = 0b00010000;
168
169        /// Number of bits in this number type
170        const NUM_BITS: u32 = 33;
171
172        let mut result: i64 = 0;
173
174        let byte = self.decode_u8()?;
175        result |= i64::from(byte & INTEGER_BIT_FLAG);
176        if byte & CONTINUATION_BIT == 0 {
177            /// before returning the result, we need to sign extend the unspecified bits
178            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 7;
179            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
180            return u32::try_from(sign_extended_result).map_err(|_| DecodingError::I33IsNegative);
181        }
182
183        let byte = self.decode_u8()?;
184        result |= i64::from(byte & INTEGER_BIT_FLAG) << 7;
185        if byte & CONTINUATION_BIT == 0 {
186            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 14;
187            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
188            return u32::try_from(sign_extended_result).map_err(|_| DecodingError::I33IsNegative);
189        }
190
191        let byte = self.decode_u8()?;
192        result |= i64::from(byte & INTEGER_BIT_FLAG) << 14;
193        if byte & CONTINUATION_BIT == 0 {
194            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 21;
195            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
196            return u32::try_from(sign_extended_result).map_err(|_| DecodingError::I33IsNegative);
197        }
198
199        let byte = self.decode_u8()?;
200        result |= i64::from(byte & INTEGER_BIT_FLAG) << 21;
201        if byte & CONTINUATION_BIT == 0 {
202            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 28;
203            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
204            return u32::try_from(sign_extended_result).map_err(|_| DecodingError::I33IsNegative);
205        }
206
207        let byte = self.decode_u8()?;
208        result |= i64::from(byte & INTEGER_BIT_FLAG) << 28;
209
210        // there can only be a maximum number of 5 bytes for a 33-bit integer
211        let has_next_byte = byte & CONTINUATION_BIT > 0;
212        if has_next_byte {
213            // TODO distinguish between both error variants
214            return Err(DecodingError::MalformedVariableLengthInteger);
215        }
216
217        // Verify that the padding and sign bits are either all ones or all
218        // zeros. To do this we count the ones and check if that number is zero
219        // or equal to the number of ones in both bitmasks combined.
220        const PADDING_AND_SIGN_BITMASK: u8 =
221            PADDING_IN_LAST_BYTE_BITMASK | SIGN_IN_LAST_BYTE_BITFLAG;
222        let number_of_ones_in_padding_and_sign_bits =
223            (byte & PADDING_AND_SIGN_BITMASK).count_ones();
224        let padding_bits_match_sign_bit = number_of_ones_in_padding_and_sign_bits
225            == PADDING_AND_SIGN_BITMASK.count_ones()
226            || number_of_ones_in_padding_and_sign_bits == 0;
227        if !padding_bits_match_sign_bit {
228            // TODO distinguish between both error variants
229            return Err(DecodingError::MalformedVariableLengthInteger);
230        }
231
232        u32::try_from(result).map_err(|_| DecodingError::I33IsNegative)
233    }
234
235    pub fn decode_f32(&mut self) -> Result<u32, DecodingError> {
236        let bytes = self.strip_bytes::<4>()?;
237        Ok(u32::from_le_bytes(bytes))
238    }
239
240    pub fn decode_var_i64(&mut self) -> Result<i64, DecodingError> {
241        /// Because up to 10 bytes (each storing 7 bits) may be used to store 64 bits,
242        /// some bits in the last byte will be left unused. This is a bitmask for
243        /// exactly these bits in the last byte.
244        const PADDING_IN_LAST_BYTE_BITMASK: u8 = 0b01111110;
245
246        /// This bitflag defines the position of the sign bit in the last byte.
247        const SIGN_IN_LAST_BYTE_BITFLAG: u8 = 0b00000001;
248
249        /// Number of bits in this number type
250        const NUM_BITS: u32 = 64;
251
252        let mut result: i64 = 0;
253
254        let byte = self.decode_u8()?;
255        result |= i64::from(byte & INTEGER_BIT_FLAG);
256        if byte & CONTINUATION_BIT == 0 {
257            /// before returning the result, we need to sign extend the unspecified bits
258            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 7;
259            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
260            return Ok(sign_extended_result);
261        }
262
263        let byte = self.decode_u8()?;
264        result |= i64::from(byte & INTEGER_BIT_FLAG) << 7;
265        if byte & CONTINUATION_BIT == 0 {
266            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 14;
267            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
268            return Ok(sign_extended_result);
269        }
270
271        let byte = self.decode_u8()?;
272        result |= i64::from(byte & INTEGER_BIT_FLAG) << 14;
273        if byte & CONTINUATION_BIT == 0 {
274            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 21;
275            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
276            return Ok(sign_extended_result);
277        }
278
279        let byte = self.decode_u8()?;
280        result |= i64::from(byte & INTEGER_BIT_FLAG) << 21;
281        if byte & CONTINUATION_BIT == 0 {
282            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 28;
283            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
284            return Ok(sign_extended_result);
285        }
286
287        let byte = self.decode_u8()?;
288        result |= i64::from(byte & INTEGER_BIT_FLAG) << 28;
289        if byte & CONTINUATION_BIT == 0 {
290            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 35;
291            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
292            return Ok(sign_extended_result);
293        }
294
295        let byte = self.decode_u8()?;
296        result |= i64::from(byte & INTEGER_BIT_FLAG) << 35;
297        if byte & CONTINUATION_BIT == 0 {
298            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 42;
299            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
300            return Ok(sign_extended_result);
301        }
302
303        let byte = self.decode_u8()?;
304        result |= i64::from(byte & INTEGER_BIT_FLAG) << 42;
305        if byte & CONTINUATION_BIT == 0 {
306            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 49;
307            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
308            return Ok(sign_extended_result);
309        }
310
311        let byte = self.decode_u8()?;
312        result |= i64::from(byte & INTEGER_BIT_FLAG) << 49;
313        if byte & CONTINUATION_BIT == 0 {
314            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 56;
315            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
316            return Ok(sign_extended_result);
317        }
318
319        let byte = self.decode_u8()?;
320        result |= i64::from(byte & INTEGER_BIT_FLAG) << 56;
321        if byte & CONTINUATION_BIT == 0 {
322            const NUM_UNSPECIFIED_BITS: u32 = NUM_BITS - 63;
323            let sign_extended_result = (result << NUM_UNSPECIFIED_BITS) >> NUM_UNSPECIFIED_BITS;
324            return Ok(sign_extended_result);
325        }
326
327        let byte = self.decode_u8()?;
328        result |= i64::from(byte & INTEGER_BIT_FLAG) << 63;
329
330        // there can only be a maximum number of 10 bytes for a 64-bit integer
331        let has_next_byte = byte & CONTINUATION_BIT > 0;
332        if has_next_byte {
333            // TODO distinguish between both error variants
334            return Err(DecodingError::MalformedVariableLengthInteger);
335        }
336
337        // Verify that the padding and sign bits are either all ones or all
338        // zeros. To do this we count the ones and check if that number is zero
339        // or equal to the number of ones in both bitmasks combined.
340        const PADDING_AND_SIGN_BITMASK: u8 =
341            PADDING_IN_LAST_BYTE_BITMASK | SIGN_IN_LAST_BYTE_BITFLAG;
342        let number_of_ones_in_padding_and_sign_bits =
343            (byte & PADDING_AND_SIGN_BITMASK).count_ones();
344        let padding_bits_match_sign_bit = number_of_ones_in_padding_and_sign_bits
345            == PADDING_AND_SIGN_BITMASK.count_ones()
346            || number_of_ones_in_padding_and_sign_bits == 0;
347        if !padding_bits_match_sign_bit {
348            // TODO distinguish between both error variants
349            return Err(DecodingError::MalformedVariableLengthInteger);
350        }
351
352        Ok(result)
353    }
354
355    /// Note: If `Err`, the [WasmDecoder] object is no longer guaranteed to be in a valid state
356    pub fn decode_name(&mut self) -> Result<&'wasm str, DecodingError> {
357        let len = self.decode_var_u32()?.into_usize();
358
359        let utf8_str = &self
360            .full_wasm_binary
361            .get(self.pc..(self.pc + len))
362            .ok_or(DecodingError::Eof)?;
363
364        self.pc += len;
365
366        core::str::from_utf8(utf8_str).map_err(DecodingError::MalformedUtf8)
367    }
368
369    // TODO remove, see note on read_vec for more info
370    pub fn decode_vec_enumerated<T, F, E>(&mut self, mut read_element: F) -> Result<Vec<T>, E>
371    where
372        T: 'wasm,
373        F: FnMut(&mut WasmDecoder<'wasm>, u32) -> Result<T, E>,
374        E: From<DecodingError>,
375    {
376        let mut idx = 0;
377        self.decode_vec(|wasm| {
378            let ret = read_element(wasm, idx);
379            idx = idx
380                .checked_add(1)
381                .expect("the length of vectors to be encoded as a u32");
382            ret
383        })
384    }
385
386    /// Note: If `Err`, the [WasmDecoder] object is no longer guaranteed to be in a valid state
387    // TODO make this return `impl ExactSizeIterator<Item = T>` to prevent allocation. This will be
388    // usedful if we want to decode some information on-demand in the future.
389    pub fn decode_vec<T, F, E>(&mut self, mut read_element: F) -> Result<Vec<T>, E>
390    where
391        T: 'wasm,
392        F: FnMut(&mut WasmDecoder<'wasm>) -> Result<T, E>,
393        E: From<DecodingError>,
394    {
395        let len = self.decode_var_u32()?;
396        core::iter::repeat_with(|| read_element(self))
397            .take(len.into_usize())
398            .collect()
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use crate::core::decoding::reader::WasmDecoder;
405
406    #[test]
407    fn test_var_i32() {
408        let bytes = [0xC0, 0xBB, 0x78];
409        let mut wasm = WasmDecoder::new(&bytes);
410
411        assert_eq!(wasm.decode_var_i32(), Ok(-123456));
412    }
413}