Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0138)
- [diff](https://github.com/getsentry/sentry-native/compare/0.13.7...0.13.8)

### Fixes

- Avoid stack overflow when deserializing large flat JSON objects([#5361](https://github.com/getsentry/sentry-java/pull/5361))
Comment thread
buenaflor marked this conversation as resolved.
Outdated

## 8.40.0

### Fixes
Expand Down
85 changes: 42 additions & 43 deletions sentry/src/main/java/io/sentry/JsonObjectDeserializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,49 +82,48 @@ private static final class TokenMap implements Token {

private void parse(@NotNull JsonObjectReader reader) throws IOException {
boolean done = false;
switch (reader.peek()) {
case BEGIN_ARRAY:
reader.beginArray();
pushCurrentToken(new TokenArray());
break;
case END_ARRAY:
reader.endArray();
done = handleArrayOrMapEnd();
break;
case BEGIN_OBJECT:
reader.beginObject();
pushCurrentToken(new TokenMap());
break;
case END_OBJECT:
reader.endObject();
done = handleArrayOrMapEnd();
break;
case NAME:
pushCurrentToken(new TokenName(reader.nextName()));
break;
case STRING:
// avoid method refs on Android due to some issues with older AGP setups
// noinspection Convert2MethodRef
done = handlePrimitive(() -> reader.nextString());
break;
case NUMBER:
done = handlePrimitive(() -> nextNumber(reader));
break;
case BOOLEAN:
// avoid method refs on Android due to some issues with older AGP setups
// noinspection Convert2MethodRef
done = handlePrimitive(() -> reader.nextBoolean());
break;
case NULL:
reader.nextNull();
done = handlePrimitive(() -> null);
break;
case END_DOCUMENT:
done = true;
break;
}
if (!done) {
parse(reader);
while (!done) {
switch (reader.peek()) {
case BEGIN_ARRAY:
reader.beginArray();
pushCurrentToken(new TokenArray());
break;
case END_ARRAY:
reader.endArray();
done = handleArrayOrMapEnd();
break;
case BEGIN_OBJECT:
reader.beginObject();
pushCurrentToken(new TokenMap());
break;
case END_OBJECT:
reader.endObject();
done = handleArrayOrMapEnd();
break;
case NAME:
pushCurrentToken(new TokenName(reader.nextName()));
break;
case STRING:
// avoid method refs on Android due to some issues with older AGP setups
// noinspection Convert2MethodRef
done = handlePrimitive(() -> reader.nextString());
break;
case NUMBER:
done = handlePrimitive(() -> nextNumber(reader));
break;
case BOOLEAN:
// avoid method refs on Android due to some issues with older AGP setups
// noinspection Convert2MethodRef
done = handlePrimitive(() -> reader.nextBoolean());
break;
case NULL:
reader.nextNull();
done = handlePrimitive(() -> null);
break;
case END_DOCUMENT:
done = true;
break;
}
}
}

Expand Down
44 changes: 44 additions & 0 deletions sentry/src/test/java/io/sentry/SentryEventTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package io.sentry
import io.sentry.exception.ExceptionMechanismException
import io.sentry.protocol.Mechanism
import io.sentry.protocol.SentryId
import java.io.StringReader
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.Collections
import java.util.concurrent.atomic.AtomicReference
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand Down Expand Up @@ -174,6 +176,48 @@ class SentryEventTest {
}
}

@Test
fun `deserializes event with large flat modules map on a small stack`() {
val moduleCount = 50000
val json = buildString {
append("{\"event_id\":\"00000000000000000000000000000000\",\"modules\":{")
repeat(moduleCount) {
if (it > 0) {
append(',')
}
append("\"m")
append(it)
append("\":\"v\"")
}
append("}}")
}

val error = AtomicReference<Throwable?>()
val event = AtomicReference<SentryEvent?>()
val thread =
Thread(
null,
Runnable {
try {
event.set(
JsonSerializer(SentryOptions())
.deserialize(StringReader(json), SentryEvent::class.java)
)
} catch (throwable: Throwable) {
error.set(throwable)
}
},
"large-flat-modules-repro",
1024L * 1024L,
)

thread.start()
thread.join()

assertNull(error.get())
assertEquals(moduleCount, event.get()?.modules?.size)
}
Comment thread
denrase marked this conversation as resolved.

@Test
fun `null tag does not cause NPE`() {
val event = SentryEvent()
Expand Down
Loading