Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArrayIndexOutOfBoundsException in Http2Connection.writeSynReset #8658

Open
metalichesky opened this issue Jan 21, 2025 · 2 comments
Open

ArrayIndexOutOfBoundsException in Http2Connection.writeSynReset #8658

metalichesky opened this issue Jan 21, 2025 · 2 comments

Comments

@metalichesky
Copy link

For a long time we have been experiencing a rare but fatal crash in our app (size, offset and byteCount may vary, but other parts stays the same):

Fatal Exception: java.lang.ArrayIndexOutOfBoundsException: size=1 offset=0 byteCount=4087
       at okio.-SegmentedByteString.checkOffsetAndCount(Util.kt:26)
       at okio.AsyncTimeout$sink$1.write(AsyncTimeout.kt:109)
       at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.kt:256)
       at okio.RealBufferedSink.writeByte(RealBufferedSink.kt:211)
       at okhttp3.internal.Util.writeMedium(Util.java:317)
       at okhttp3.internal.http2.Http2Writer.frameHeader(Http2Writer.kt:261)
       at okhttp3.internal.http2.Http2Writer.rstStream(Http2Writer.kt:128)
       at okhttp3.internal.http2.Http2Connection.writeSynReset$okhttp(Http2Connection.java:354)
       at okhttp3.internal.http2.Http2Connection$writeSynResetLater$$inlined$execute$default$1.runOnce(TaskQueue.kt:220)
       at okhttp3.internal.concurrent.TaskRunner.runTask(TaskRunner.kt:116)
       at okhttp3.internal.concurrent.TaskRunner.access$runTask(TaskRunner.kt:42)
       at okhttp3.internal.concurrent.TaskRunner$runnable$1.run(TaskRunner.kt:65)
       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:919)

For which we do not have a clear reproducible example. It is not entirely clear what exactly happens from the stack trace and analytics logs. However, judging by other logs from our analytics system, users experience this crash when switching content in the Exoplayer audio player when playing various audio streams over the Internet. It is possible that the same address is used for both audio tracks and the http2 connection is reused.

Currently we use our own DataSource implementation based on OkHttp 4.12.0 and okio 3.9.0, but face it with previous versions too.
There is no correlation with Android OS versions and device vendors found.

This exception is not handled in any way and is not passed to the application for handling, which violates the principle of defensive programming and does not allow steps to be taken to restore the application's functionality.

Why writeSynResetLater called for a network connection?
If such an exception occurs when calling writeSynReset, then maybe it is possible to catch such exceptions at the library level and stop the connection by calling Http2Connection.failConnection and then removing this connection from the connection pool?
So after requesting stream again OkHttp will create new connection instead of the broken one.

@metalichesky metalichesky changed the title ArrayIndexOutOfBoundsException in okHttp2Connection.writeSynReset ArrayIndexOutOfBoundsException in Http2Connection.writeSynReset Jan 21, 2025
@yschimke
Copy link
Collaborator

Usually this sort of exception is caused by unsafe threading.

Since it's ExoPlayer, it could be interrupts. There is a workaround in this fix androidx/media@80928e7

Which version of ExoPlayer are you using?

@metalichesky
Copy link
Author

We uses exoplayer from 1.3.1, but without okhttp extension (custom DataSource with OkHttp usage).
Indeed, currently our stream request looks like old version without your workaround:

    val request = Request.Builder().url(streamUrl).build()
    val response = okHttpClient.newCall(request).execute()

Will try using enqueue and getting future result with call cancelling, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants