From 95b8e5a106131fb1b09915ecadcb41b26ac07a6c Mon Sep 17 00:00:00 2001 From: Ismail Ramzi Date: Thu, 27 Aug 2026 14:04:43 +0530 Subject: [PATCH] fix undefined 32-bit shift in dwarf LEB128 decoding --- .../Unwind/Dwarf/FIRCLSDataParsing.c | 6 +++--- Crashlytics/UnitTests/FIRCLSDwarfTests.m | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c b/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c index 2bb37c1b7ad..b79b274e84a 100644 --- a/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c +++ b/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c @@ -98,7 +98,7 @@ uint64_t FIRCLSParseULEB128AndAdvance(const void** cursor) { *cursor += 1; - result |= ((0x7F & byte) << shift); + result |= ((uint64_t)(0x7F & byte) << shift); if ((0x80 & byte) == 0) { break; } @@ -120,7 +120,7 @@ int64_t FIRCLSParseLEB128AndAdvance(const void** cursor) { *cursor += 1; - result |= ((0x7F & byte) << shift); + result |= ((uint64_t)(0x7F & byte) << shift); shift += 7; /* sign bit of byte is second high order bit (0x40) */ @@ -131,7 +131,7 @@ int64_t FIRCLSParseLEB128AndAdvance(const void** cursor) { if ((shift < size) && (0x40 & byte)) { // sign extend - result |= -(1 << shift); + result |= -((uint64_t)1 << shift); } return result; diff --git a/Crashlytics/UnitTests/FIRCLSDwarfTests.m b/Crashlytics/UnitTests/FIRCLSDwarfTests.m index 88ab9c8ec6e..b9b9e814ad6 100644 --- a/Crashlytics/UnitTests/FIRCLSDwarfTests.m +++ b/Crashlytics/UnitTests/FIRCLSDwarfTests.m @@ -21,6 +21,7 @@ #include "Crashlytics/Crashlytics/Components/FIRCLSContext.h" #include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" #include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h" #include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h" #include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" @@ -172,6 +173,25 @@ - (void)testAssignReturnRegisterNumber { XCTAssertEqual(FIRCLSDwarfUnwindGetRegisterValue(&outputRegisters, CLS_DWARF_REG_RETURN), 777); } +- (void)testParseULEB128DecodesValueWiderThan28Bits { + // ULEB128 of 0xFFFFFFFF needs 5 bytes; the fifth byte lands at shift 28, so + // decoding the 0x7F chunk as a 32-bit int shifts past the sign bit. + const uint8_t encoded[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0F}; + const void* cursor = encoded; + + XCTAssertEqual(FIRCLSParseULEB128AndAdvance(&cursor), 0xFFFFFFFFULL); + XCTAssertEqual(cursor, (const void*)(encoded + sizeof(encoded))); +} + +- (void)testParseLEB128DecodesLargeNegativeValue { + // SLEB128 of -2^32; the sign-extension and the value chunks both shift past 32. + const uint8_t encoded[] = {0x80, 0x80, 0x80, 0x80, 0x70}; + const void* cursor = encoded; + + XCTAssertEqual(FIRCLSParseLEB128AndAdvance(&cursor), -4294967296LL); + XCTAssertEqual(cursor, (const void*)(encoded + sizeof(encoded))); +} + #endif @end