diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e7e2e1e6e..cee15206010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ This version adds a dependency on Swift. We renamed the default branch from `mas ### Fixes -- Support uint64 in crash reports (#2631) +- Support uint64 in crash reports (#2631, #2642) - Always fetch view hierarchy on the main thread (#2629) - Carthage Xcode 14 compatibility issue (#2636) - Crash in CppException Monitor (#2639) diff --git a/Sources/SentryCrash/Recording/SentryCrashReport.c b/Sources/SentryCrash/Recording/SentryCrashReport.c index 8cedc8edc39..346a66636c8 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReport.c +++ b/Sources/SentryCrash/Recording/SentryCrashReport.c @@ -134,7 +134,7 @@ static void addUIntegerElement( const SentryCrashReportWriter *const writer, const char *const key, const uint64_t value) { - sentrycrashjson_addIntegerElement(getJsonContext(writer), key, (int64_t)value); + sentrycrashjson_addUIntegerElement(getJsonContext(writer), key, value); } static void diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c index 741c5df5ea7..450047c8a26 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c @@ -335,6 +335,17 @@ sentrycrashjson_addIntegerElement( return addJSONData(context, buff, (int)strlen(buff)); } +int +sentrycrashjson_addUIntegerElement( + SentryCrashJSONEncodeContext *const context, const char *const name, uint64_t value) +{ + int result = sentrycrashjson_beginElement(context, name); + unlikely_if(result != SentryCrashJSON_OK) { return result; } + char buff[30]; + sprintf(buff, "%" PRIu64, value); + return addJSONData(context, buff, (int)strlen(buff)); +} + int sentrycrashjson_addNullElement(SentryCrashJSONEncodeContext *const context, const char *const name) { @@ -1217,6 +1228,12 @@ decodeElement(const char *const name, SentryCrashJSONDecodeContext *context) } } + if (!isFPChar(*context->bufferPtr) && !isOverflow) { + if (sign == 1 && accum <= ULLONG_MAX) { + return context->callbacks->onUIntegerElement(name, accum, context->userData); + } + } + while (context->bufferPtr < context->bufferEnd && isFPChar(*context->bufferPtr)) { context->bufferPtr++; } @@ -1354,6 +1371,16 @@ addJSONFromFile_onIntegerElement(const char *const name, const int64_t value, vo return result; } +static int +addJSONFromFile_onUIntegerElement( + const char *const name, const uint64_t value, void *const userData) +{ + JSONFromFileContext *context = (JSONFromFileContext *)userData; + int result = sentrycrashjson_addUIntegerElement(context->encodeContext, name, value); + context->updateDecoderCallback(context); + return result; +} + static int addJSONFromFile_onNullElement(const char *const name, void *const userData) { @@ -1423,6 +1450,7 @@ sentrycrashjson_addJSONFromFile(SentryCrashJSONEncodeContext *const encodeContex .onEndData = addJSONFromFile_onEndData, .onFloatingPointElement = addJSONFromFile_onFloatingPointElement, .onIntegerElement = addJSONFromFile_onIntegerElement, + .onUIntegerElement = addJSONFromFile_onUIntegerElement, .onNullElement = addJSONFromFile_onNullElement, .onStringElement = addJSONFromFile_onStringElement, }; @@ -1480,6 +1508,7 @@ sentrycrashjson_addJSONElement(SentryCrashJSONEncodeContext *const encodeContext .onEndData = addJSONFromFile_onEndData, .onFloatingPointElement = addJSONFromFile_onFloatingPointElement, .onIntegerElement = addJSONFromFile_onIntegerElement, + .onUIntegerElement = addJSONFromFile_onUIntegerElement, .onNullElement = addJSONFromFile_onNullElement, .onStringElement = addJSONFromFile_onStringElement, }; diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h index 11212e335db..6cda5ad513a 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.h @@ -161,6 +161,19 @@ int sentrycrashjson_addBooleanElement( int sentrycrashjson_addIntegerElement( SentryCrashJSONEncodeContext *context, const char *name, int64_t value); +/** Add an unsigned integer element. + * + * @param context The encoding context. + * + * @param name The element's name. + * + * @param value The element's value. + * + * @return SentryCrashJSON_OK if the process was successful. + */ +int sentrycrashjson_addUIntegerElement( + SentryCrashJSONEncodeContext *context, const char *name, uint64_t value); + /** Add a floating point element. * * @param context The encoding context. @@ -416,6 +429,19 @@ typedef struct SentryCrashJSONDecodeCallbacks { */ int (*onIntegerElement)(const char *name, int64_t value, void *userData); + /** Called when an unsigned integer element is decoded. + * + * @param name The element's name. + * + * @param value The element's value. + * + * @param userData Data that was specified when calling + * sentrycrashjson_decode(). + * + * @return SentryCrashJSON_OK if decoding should continue. + */ + int (*onUIntegerElement)(const char *name, uint64_t value, void *userData); + /** Called when a null element is decoded. * * @param name The element's name. diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodecObjC.m b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodecObjC.m index 6f24e3d8886..0e81e382995 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodecObjC.m +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodecObjC.m @@ -138,6 +138,7 @@ - (id)initWithEncodeOptions:(SentryCrashJSONEncodeOption)encodeOptions self.callbacks->onEndData = onEndData; self.callbacks->onFloatingPointElement = onFloatingPointElement; self.callbacks->onIntegerElement = onIntegerElement; + self.callbacks->onUIntegerElement = onUIntegerElement; self.callbacks->onNullElement = onNullElement; self.callbacks->onStringElement = onStringElement; @@ -231,6 +232,15 @@ - (void)dealloc return onElement(codec, name, element); } +static int +onUIntegerElement(const char *const cName, const uint64_t value, void *const userData) +{ + NSString *name = stringFromCString(cName); + id element = [NSNumber numberWithUnsignedLongLong:value]; + SentryCrashJSONCodec *codec = (__bridge SentryCrashJSONCodec *)userData; + return onElement(codec, name, element); +} + static int onNullElement(const char *const cName, void *const userData) { diff --git a/Tests/SentryTests/SentryCrash/SentryCrashJSONCodec_Tests.m b/Tests/SentryTests/SentryCrash/SentryCrashJSONCodec_Tests.m index ffa148a0afe..bdccc7a5386 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashJSONCodec_Tests.m +++ b/Tests/SentryTests/SentryCrash/SentryCrashJSONCodec_Tests.m @@ -1296,15 +1296,24 @@ - (void)testDeserializeArray_64IntMax XCTAssertEqual([result[0] longLongValue], value); } -- (void)testDeserializeArrayUIntMax_UsesDouble +- (void)testDeserializeArrayIntMaxPlusOne_UsesUInt +{ + uint64_t value = (uint64_t)LLONG_MAX + 1; + NSString *jsonString = [NSString stringWithFormat:@"[%llu]", value]; + + NSArray *result = [self decode:jsonString]; + + XCTAssertEqual([result[0] unsignedLongLongValue], value); +} + +- (void)testDeserializeArrayUIntMax_UsesUInt { uint64_t value = ULLONG_MAX; NSString *jsonString = [NSString stringWithFormat:@"[%llu]", value]; NSArray *result = [self decode:jsonString]; - XCTAssertNotEqual([result[0] unsignedLongLongValue], value); - XCTAssertEqual([result[0] doubleValue], [@(value) doubleValue]); + XCTAssertEqual([result[0] unsignedLongLongValue], value); } - (void)testDeserializeArray_NegativeLLONG_MIN_plusOne_UsesDouble @@ -1566,7 +1575,7 @@ - (void)testAddJSONFromBigFile { NSString *savedFilename = [self.tempPath stringByAppendingPathComponent:@"big.json"]; id savedObject = @{ - @"an_array" : @[ @1, @2, @3, @4 ], + @"an_array" : @[ @1, @2, @3, @4, @1.3, @(YES), @(LLONG_MIN), @(ULLONG_MAX) ], @"lines" : @[ @"I cannot describe to you my sensations on the near prospect of my undertaking.", @"It is impossible to communicate to you a conception of the trembling sensation, half pleasurable and half fearful, with which I am preparing to depart.",