diff options
author | Thomas Lively <tlively@google.com> | 2024-06-18 19:12:36 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-19 02:12:36 +0000 |
commit | 3acacac34c9ebe949fbc7d9eb3649266760104fe (patch) | |
tree | ad2be5a7961ff5d6e31dc650f9804f40ae0a8f97 /src | |
parent | eceb0fb6ac097e262bf74dcdb686cfc5d4c55188 (diff) | |
download | binaryen-3acacac34c9ebe949fbc7d9eb3649266760104fe.tar.gz binaryen-3acacac34c9ebe949fbc7d9eb3649266760104fe.tar.bz2 binaryen-3acacac34c9ebe949fbc7d9eb3649266760104fe.zip |
Fix validation of unused LEB128 bits (#6680)
The unused bits must be a sign extension of the significant value, but we were
previously only validating that unsigned LEBs had their unused bytes set to
zero. Re-enable the spec test that checks for proper validation.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-binary.h | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 3870ccf7f..46d81064e 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -102,16 +102,22 @@ template<typename T, typename MiniT> struct LEB { bool last = !(byte & 128); T payload = byte & 127; using mask_type = typename std::make_unsigned<T>::type; - auto shift_mask = 0 == shift - ? ~mask_type(0) - : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u); - T significant_payload = payload & shift_mask; - if (significant_payload != payload) { - if (!(std::is_signed<T>::value && last)) { - throw ParseException("LEB dropped bits only valid for signed LEB"); + auto payload_mask = 0 == shift + ? ~mask_type(0) + : ((mask_type(1) << (sizeof(T) * 8 - shift)) - 1u); + T significant_payload = payload_mask & payload; + value |= significant_payload << shift; + T unused_bits_mask = ~payload_mask & 127; + T unused_bits = payload & unused_bits_mask; + if (std::is_signed_v<T> && value < 0) { + if (unused_bits != unused_bits_mask) { + throw ParseException("Unused negative LEB bits must be 1s"); + } + } else { + if (unused_bits != 0) { + throw ParseException("Unused non-negative LEB bits must be 0s"); } } - value |= significant_payload << shift; if (last) { break; } @@ -120,9 +126,8 @@ template<typename T, typename MiniT> struct LEB { throw ParseException("LEB overflow"); } } - // If signed LEB, then we might need to sign-extend. (compile should - // optimize this out if not needed). - if (std::is_signed<T>::value) { + // If signed LEB, then we might need to sign-extend. + if constexpr (std::is_signed_v<T>) { shift += 7; if ((byte & 64) && size_t(shift) < 8 * sizeof(T)) { size_t sext_bits = 8 * sizeof(T) - size_t(shift); |