google / google/gson

TreeTypeAdapter.read() may incorrectly hide IOException from InputStream as JsonIOException

Open
#1,907 1 comment 1 reaction 0 assignees View on GitHub
bug
Dominant language
Java
Stars
24.2k
Forks
4.5k
Avg merge
6d 4h
Merged PRs (30d)
12

Description

`TreeTypeAdapter.read()` calls `Streams.parse()` which can cause its `Reader`'s `InputStream` to throw an `IOException`, which is obfuscated as a `JsonIOException` `RuntimeException`, which can result in a crash at runtime. For example, if the `Reader` is created from an HTTP response body `InputStream` and the response times out with a `SocketTimeoutException` while reading the response body.

The [assumption made](https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/Streams.java#L57) in `Streams.parse()` that

> The stream ended prematurely so it is likely a syntax error.

does not always hold true.

I discovered this when I ran into this crash:

```
Fatal Exception: com.google.gson.JsonIOException: java.net.SocketTimeoutException: timeout
at com.google.gson.internal.Streams.parse(Streams.java:62)
at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:65)
at com.google.gson.TypeAdapter.fromJson(TypeAdapter.java:260)
at com.auth0.android.request.internal.GsonAdapter.fromJson(GsonAdapter.kt:58)
at com.auth0.android.request.internal.BaseRequest.execute(BaseRequest.kt:99)
at com.auth0.android.request.internal.BaseRequest$start$1.run(BaseRequest.kt:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by java.net.SocketTimeoutException: timeout
at okhttp3.internal.http2.Http2Stream$StreamTimeout.newTimeoutException(Http2Stream.kt:677)
at okhttp3.internal.http2.Http2Stream$StreamTimeout.exitAndThrowIfTimedOut(Http2Stream.kt:686)
at okhttp3.internal.http2.Http2Stream$FramingSource.read(Http2Stream.kt:382)
at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:276)
at okio.RealBufferedSource.read(RealBufferedSource.kt:189)
at okio.RealBufferedSource.exhausted(RealBufferedSource.kt:197)
at okio.InflaterSource.refill(InflaterSource.kt:112)
at okio.InflaterSource.readOrInflate(InflaterSource.kt:76)
at okio.InflaterSource.read(InflaterSource.kt:49)
at okio.GzipSource.read(GzipSource.kt:69)
at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:158)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:291)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:355)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:181)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at com.google.gson.stream.JsonReader.fillBuffer(JsonReader.java:1289)
at com.google.gson.stream.JsonReader.nextQuotedValue(JsonReader.java:1029)
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:814)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:702)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:715)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:723)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:715)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:723)
at com.google.gson.internal.bind.TypeAdapters$29.read(TypeAdapters.java:698)
at com.google.gson.internal.Streams.parse(Streams.java:48)
at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:65)
at com.google.gson.TypeAdapter.fromJson(TypeAdapter.java:260)
at com.auth0.android.request.internal.GsonAdapter.fromJson(GsonAdapter.kt:58)
at com.auth0.android.request.internal.BaseRequest.execute(BaseRequest.kt:99)
at com.auth0.android.request.internal.BaseRequest$start$1.run(BaseRequest.kt:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.