@@ -1247,40 +1247,61 @@ LEBType WasmBinaryReader::LEB128(uint32 &length)
12471247 constexpr bool sign = LEBType (-1 ) < LEBType (0 );
12481248 LEBType result = 0 ;
12491249 uint32 shift = 0 ;
1250- byte b = 0 ;
1250+ byte b = 0x80 ;
12511251 length = 0 ;
1252- constexpr uint32 maxReads = (uint32) ((( bits % 7 ) == 0 ) ? bits/ 7 : bits/ 7 + 1 );
1253- CompileAssert (maxReads > 0 );
1252+ constexpr uint32 maxBytes = (uint32)(( bits + 6 ) / 7 );
1253+ CompileAssert (maxBytes > 0 );
12541254
1255- for (uint32 i = 0 ; i < maxReads; ++i)
1255+ uint32 iByte = 0 ;
1256+ for (; iByte < maxBytes && (b & 0x80 ) == 0x80 ; ++iByte)
12561257 {
12571258 CheckBytesLeft (1 );
12581259 b = *m_pc++;
1259- ++length;
12601260 result = result | ((LEBType)(b & 0x7f ) << shift);
1261- if (sign)
1262- {
1263- shift += 7 ;
1264- if ((b & 0x80 ) == 0 )
1265- break ;
1266- }
1267- else
1268- {
1269- if ((b & 0x80 ) == 0 )
1270- break ;
1271- shift += 7 ;
1272- }
1261+ shift += 7 ;
12731262 }
12741263
1275- if (b & 0x80 || m_pc > m_end )
1264+ if (( b & 0x80 ) == 0x80 )
12761265 {
12771266 ThrowDecodingError (_u (" Invalid LEB128 format" ));
12781267 }
12791268
1280- if (sign && (shift < (sizeof (LEBType) * 8 )) && (0x40 & b))
1269+ const bool isLastByte = iByte == maxBytes;
1270+ constexpr bool hasExtraBits = (maxBytes * 7 ) != bits;
1271+ if (hasExtraBits && isLastByte)
1272+ {
1273+ // A signed-LEB128 must sign-extend the final byte, excluding its most-significant bit
1274+ // For unsigned values, the extra bits must be all zero.
1275+ // For signed values, the extra bits *plus* the most significant bit must either be 0, or all ones.
1276+
1277+ // e.g. for a 32-bit LEB128:
1278+ // bitsInLastByte = 4 (== 32 - (5-1) * 7)
1279+ // 0bYYYXXXX where Y are extra bits and X are bits included in LEB128
1280+ // if signed: check if 0bYYYXXXX is 0b0000XXX or 0b1111XXX
1281+ // is unsigned: check if 0bYYYXXXX is 0b000XXXX
1282+
1283+ constexpr int bitsInLastByte = bits - (maxBytes - 1 ) * 7 ;
1284+ constexpr int lastBitToCheck = bitsInLastByte - (sign ? 1 : 0 );
1285+ constexpr byte signExtendedExtraBits = 0x7f & (0xFF << lastBitToCheck);
1286+ const byte checkedBits = b & (0xFF << lastBitToCheck);
1287+ bool validExtraBits =
1288+ checkedBits == 0 ||
1289+ (sign && checkedBits == signExtendedExtraBits);
1290+ if (!validExtraBits)
1291+ {
1292+ ThrowDecodingError (_u (" Invalid LEB128 format" ));
1293+ }
1294+ }
1295+
1296+ length = iByte;
1297+ if (sign)
12811298 {
1282- #pragma prefast(suppress:26453)
1283- result |= ((~(LEBType)0 ) << shift);
1299+ // Perform sign extension
1300+ const int signExtendShift = (sizeof (LEBType) * 8 ) - shift;
1301+ if (signExtendShift > 0 )
1302+ {
1303+ result = static_cast <LEBType>(result << signExtendShift) >> signExtendShift;
1304+ }
12841305 }
12851306 return result;
12861307}
0 commit comments