Skip to content

Commit 15b8c61

Browse files
fix: Support uint64 in crash reports (#2631)
Add support for uint64 when decoding crash reports.
1 parent 302ee8b commit 15b8c61

File tree

3 files changed

+112
-35
lines changed

3 files changed

+112
-35
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
- AttachScreenshots is GA (#2623)
88
- Gather profiling timeseries metrics for CPU usage and memory footprint (#2493)
99

10+
### Fixes
11+
12+
- Support uint64 in crash reports (#2631)
13+
1014
## 8.0.0
1115

1216
### Features

Sources/SentryCrash/Recording/Tools/SentryCrashJSONCodec.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <errno.h>
3131
#include <fcntl.h>
3232
#include <inttypes.h>
33+
#include <limits.h>
3334
#include <math.h>
3435
#include <stdio.h>
3536
#include <string.h>
@@ -1190,17 +1191,17 @@ decodeElement(const char *const name, SentryCrashJSONDecodeContext *context)
11901191
case '8':
11911192
case '9': {
11921193
// Try integer conversion.
1193-
int64_t accum = 0;
1194+
uint64_t accum = 0;
1195+
bool isOverflow = false;
11941196
const char *const start = context->bufferPtr;
11951197

11961198
for (; context->bufferPtr < context->bufferEnd && isdigit(*context->bufferPtr);
11971199
context->bufferPtr++) {
1198-
accum = accum * 10 + (*context->bufferPtr - '0');
1199-
unlikely_if(accum < 0)
1200-
{
1201-
// Overflow
1202-
break;
1203-
}
1200+
unlikely_if((isOverflow = accum > (ULLONG_MAX / 10))) { break; }
1201+
accum *= 10;
1202+
int nextDigit = (*context->bufferPtr - '0');
1203+
unlikely_if((isOverflow = accum > (ULLONG_MAX - nextDigit))) { break; }
1204+
accum += nextDigit;
12041205
}
12051206

12061207
unlikely_if(context->bufferPtr >= context->bufferEnd)
@@ -1209,9 +1210,11 @@ decodeElement(const char *const name, SentryCrashJSONDecodeContext *context)
12091210
return SentryCrashJSON_ERROR_INCOMPLETE;
12101211
}
12111212

1212-
if (!isFPChar(*context->bufferPtr) && accum >= 0) {
1213-
accum *= sign;
1214-
return context->callbacks->onIntegerElement(name, accum, context->userData);
1213+
if (!isFPChar(*context->bufferPtr) && !isOverflow) {
1214+
if ((sign == -1 && accum <= ((uint64_t)LLONG_MIN)) || accum <= ((uint64_t)LLONG_MAX)) {
1215+
int64_t signedAccum = accum * sign;
1216+
return context->callbacks->onIntegerElement(name, signedAccum, context->userData);
1217+
}
12151218
}
12161219

12171220
while (context->bufferPtr < context->bufferEnd && isFPChar(*context->bufferPtr)) {

Tests/SentryTests/SentryCrash/SentryCrashJSONCodec_Tests.m

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -126,55 +126,56 @@ - (void)testSerializeDeserializeArrayInteger
126126
{
127127
NSError *error = (NSError *)self;
128128
NSString *expected = @"[1]";
129-
id original = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], nil];
129+
int value = 1;
130+
NSArray<NSNumber *> *original = [NSArray arrayWithObjects:[NSNumber numberWithInt:value], nil];
130131
NSString *jsonString = toString([SentryCrashJSONCodec encode:original
131132
options:SentryCrashJSONEncodeOptionSorted
132133
error:&error]);
133-
XCTAssertNotNil(jsonString, @"");
134-
XCTAssertNil(error, @"");
135-
XCTAssertEqualObjects(jsonString, expected, @"");
134+
XCTAssertNotNil(jsonString);
135+
XCTAssertNil(error);
136+
XCTAssertEqualObjects(jsonString, expected);
136137
id result = [SentryCrashJSONCodec decode:toData(jsonString) options:0 error:&error];
137-
XCTAssertNotNil(result, @"");
138-
XCTAssertNil(error, @"");
139-
XCTAssertEqualObjects(result, original, @"");
138+
XCTAssertNotNil(result);
139+
XCTAssertNil(error);
140+
XCTAssertEqualObjects(result, original);
140141
}
141142

142143
- (void)testSerializeDeserializeArrayFloat
143144
{
144145
NSError *error = (NSError *)self;
146+
float value = -0.2f;
145147
NSString *expected = @"[-0.2]";
146-
id original = [NSArray arrayWithObjects:[NSNumber numberWithFloat:-0.2f], nil];
148+
NSArray<NSNumber *> *original =
149+
[NSArray arrayWithObjects:[NSNumber numberWithFloat:value], nil];
147150
NSString *jsonString = toString([SentryCrashJSONCodec encode:original
148151
options:SentryCrashJSONEncodeOptionSorted
149152
error:&error]);
150-
XCTAssertNotNil(jsonString, @"");
151-
XCTAssertNil(error, @"");
152-
XCTAssertEqualObjects(jsonString, expected, @"");
153+
XCTAssertNotNil(jsonString);
154+
XCTAssertNil(error);
155+
XCTAssertEqualObjects(jsonString, expected);
153156
id result = [SentryCrashJSONCodec decode:toData(jsonString) options:0 error:&error];
154-
XCTAssertNotNil(result, @"");
155-
XCTAssertNil(error, @"");
156-
XCTAssertEqual([[result objectAtIndex:0] floatValue], -0.2f, @"");
157-
// This always fails on NSNumber filled with float.
158-
// XCTAssertEqualObjects(result, original, @"");
157+
XCTAssertNotNil(result);
158+
XCTAssertNil(error);
159+
XCTAssertEqual([[result objectAtIndex:0] floatValue], value);
159160
}
160161

161162
- (void)testSerializeDeserializeArrayFloat2
162163
{
163164
NSError *error = (NSError *)self;
164165
NSString *expected = @"[-2e-15]";
165-
id original = [NSArray arrayWithObjects:[NSNumber numberWithFloat:-2e-15f], nil];
166+
float value = -2e-15f;
167+
NSArray<NSNumber *> *original =
168+
[NSArray arrayWithObjects:[NSNumber numberWithFloat:value], nil];
166169
NSString *jsonString = toString([SentryCrashJSONCodec encode:original
167170
options:SentryCrashJSONEncodeOptionSorted
168171
error:&error]);
169-
XCTAssertNotNil(jsonString, @"");
170-
XCTAssertNil(error, @"");
171-
XCTAssertEqualObjects(jsonString, expected, @"");
172+
XCTAssertNotNil(jsonString);
173+
XCTAssertNil(error);
174+
XCTAssertEqualObjects(jsonString, expected);
172175
id result = [SentryCrashJSONCodec decode:toData(jsonString) options:0 error:&error];
173-
XCTAssertNotNil(result, @"");
174-
XCTAssertNil(error, @"");
175-
XCTAssertEqual([[result objectAtIndex:0] floatValue], -2e-15f, @"");
176-
// This always fails on NSNumber filled with float.
177-
// XCTAssertEqualObjects(result, original, @"");
176+
XCTAssertNotNil(result);
177+
XCTAssertNil(error);
178+
XCTAssertEqual([[result objectAtIndex:0] floatValue], value);
178179
}
179180

180181
- (void)testSerializeDeserializeArrayString
@@ -1275,6 +1276,64 @@ - (void)testDeserializeArrayNumberOverflow
12751276
XCTAssertNil(error, @"");
12761277
}
12771278

1279+
- (void)testDeserializeArray_Int64Min
1280+
{
1281+
int64_t value = LLONG_MIN;
1282+
NSString *jsonString = [NSString stringWithFormat:@"[%lld]", value];
1283+
1284+
NSArray<NSNumber *> *result = [self decode:jsonString];
1285+
1286+
XCTAssertEqual([result[0] longLongValue], value);
1287+
}
1288+
1289+
- (void)testDeserializeArray_64IntMax
1290+
{
1291+
int64_t value = LLONG_MAX;
1292+
NSString *jsonString = [NSString stringWithFormat:@"[%lld]", value];
1293+
1294+
NSArray<NSNumber *> *result = [self decode:jsonString];
1295+
1296+
XCTAssertEqual([result[0] longLongValue], value);
1297+
}
1298+
1299+
- (void)testDeserializeArrayUIntMax_UsesDouble
1300+
{
1301+
uint64_t value = ULLONG_MAX;
1302+
NSString *jsonString = [NSString stringWithFormat:@"[%llu]", value];
1303+
1304+
NSArray<NSNumber *> *result = [self decode:jsonString];
1305+
1306+
XCTAssertNotEqual([result[0] unsignedLongLongValue], value);
1307+
XCTAssertEqual([result[0] doubleValue], [@(value) doubleValue]);
1308+
}
1309+
1310+
- (void)testDeserializeArray_NegativeLLONG_MIN_plusOne_UsesDouble
1311+
{
1312+
uint64_t value = (uint64_t)LLONG_MIN + 1;
1313+
NSString *jsonString = [NSString stringWithFormat:@"[-%llu]", value];
1314+
1315+
NSArray<NSNumber *> *result = [self decode:jsonString];
1316+
1317+
XCTAssertNotEqual([result[0] unsignedLongLongValue], value);
1318+
XCTAssertEqual([result[0] doubleValue], -[@(value) doubleValue]);
1319+
}
1320+
1321+
- (void)testDeserializeArray_UIntOverflow_UsesDouble
1322+
{
1323+
NSError *error = (NSError *)self;
1324+
uint64_t ullongmax = ULLONG_MAX;
1325+
double value = (double)ULLONG_MAX + 1;
1326+
NSLog(@"%f, %llu", value, ullongmax);
1327+
NSString *jsonString = [NSString stringWithFormat:@"[%f]", value];
1328+
NSArray<NSNumber *> *result = [SentryCrashJSONCodec decode:toData(jsonString)
1329+
options:0
1330+
error:&error];
1331+
XCTAssertNotNil(result);
1332+
XCTAssertNil(error);
1333+
1334+
XCTAssertEqual([result[0] doubleValue], value);
1335+
}
1336+
12781337
- (void)testDeserializeDictionaryInvalidKey
12791338
{
12801339
NSError *error = (NSError *)self;
@@ -1592,4 +1651,15 @@ - (void)testDontCloseLastContainer
15921651
[self expectEquivalentJSON:encodedData.bytes toJSON:expectedJson];
15931652
}
15941653

1654+
- (NSArray<NSNumber *> *)decode:(NSString *)jsonString
1655+
{
1656+
NSError *error = nil;
1657+
NSArray<NSNumber *> *result = [SentryCrashJSONCodec decode:toData(jsonString)
1658+
options:0
1659+
error:&error];
1660+
XCTAssertNotNil(result);
1661+
XCTAssertNil(error);
1662+
return result;
1663+
}
1664+
15951665
@end

0 commit comments

Comments
 (0)