TreeTypeAdapter.read() may incorrectly hide IOException from InputStream as JsonIOException
- 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
Assessment
This issue has not been assessed yet.