Transformer: native SIGSEGV in `memcpy` while `SampleDataQueue` copies a sample into the decoder's input buffer (`DefaultCodec` has no guard like c57f96c92a)

オープン
#3,537 コメント 1 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 4 日以内に返信

@droid-girl がすでに取り組んでいます。

2026年11月11日 から。

評価

この issue はまだ評価されていません。

説明

bug editing
Version

Media3 1.11.0

More version details

media3-transformer, media3-effect, media3-exoplayer 1.11.0, default ExoPlayerAssetLoader and DefaultCodec (no custom codec factory on the decoder side). DefaultCodec is unchanged on this path in 1.11.1 and 1.12.0-alpha02 (maybeDequeueInputBuffer still hands out MediaCodec.getInputBuffer(index) with no guard), so we believe it is still open there.

Devices that reproduce the issue

From Play Console crash reports (one report each, we cannot reproduce it ourselves):

  • Honor X8b (HNLLY-Q), Android 14
  • vivo Y21d (V2520), Android 15
Devices that do not reproduce the issue

Not known. We have never seen it on our own test devices (Samsung Galaxy S24 FE, Galaxy Tab S9 FE).

Reproducible in the demo app?

Not tested

Reproduction steps

We have no deterministic steps. What the two reports have in common:

  1. A Transformer transcode reads a local MP4 through the default ExoPlayerAssetLoader (one of the two is a clipped MediaItem, ClippingConfiguration with an end position, a few seconds' sample).
  2. The decoder is DefaultCodec, driving MediaCodec synchronously on the playback thread.
  3. Both phones are low-end devices, where few codec instances are available.

Our hypothesis, which we have not confirmed: the platform frees the codec's input buffers on its own thread (a resource reclaim, CodecException.ERROR_RECLAIMED, or a fatal codec error / media service death) while ExoAssetLoaderBaseRenderer.readInput is still copying a sample into the ByteBuffer that DefaultCodec.maybeDequeueInputBuffer got from MediaCodec.getInputBuffer(index).

Why we think the platform is involved and not Media3's own release: the source of the copy is a Java byte[] (cannot be unmapped), DirectByteBuffer.put bounds-checks first (an overflow would throw, not fault), and the only Media3 path that frees the decoder (ExoAssetLoaderBaseRenderer.onReset() → decoder.release()) runs on the same playback thread that is inside render(), so it cannot interleave with the copy. A Transformer.cancel() ends on Transformer's internal thread, whose ExoPlayerAssetLoader.release() → player.release() runs that reset on the same playback thread.

Expected result

A codec that the platform reclaims or kills mid-transcode surfaces as an ExportException (decoding failed / codec reclaimed), as it does when the next MediaCodec call throws.

Actual result

The process dies with a native SIGSEGV in memcpy, inside GetByteArrayRegion, under SampleDataQueue.readData. Stack from the Android 15 report, deobfuscated with our R8 map (the Android 14 one is the same path without the clipping frame):

signal 11 (SIGSEGV)
#00 libc.so  (__memcpy_aarch64_simd+248)
#01 libart.so (art::JNI<false>::GetByteArrayRegion(_JNIEnv*, _jbyteArray*, int, int, signed char*)+228)
#02 boot.oat (art_jni_trampoline+128)
#03 boot.oat (java.nio.DirectByteBuffer.put+228)
#05 androidx.media3.exoplayer.source.SampleDataQueue.readData
#07 androidx.media3.exoplayer.source.SampleDataQueue.readSampleData
#08 androidx.media3.exoplayer.source.ProgressiveMediaPeriod$SampleStreamImpl.readData
#10 androidx.media3.exoplayer.source.ClippingMediaPeriod$ClippingSampleStream.readData
#12 androidx.media3.exoplayer.BaseRenderer.readSource
#13 androidx.media3.transformer.ExoAssetLoaderBaseRenderer.readInput
#15 androidx.media3.transformer.ExoAssetLoaderBaseRenderer.feedDecoderFromInput
#17 androidx.media3.transformer.ExoAssetLoaderBaseRenderer.render
#18 androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork
#20 androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage
#21 android.os.Handler.dispatchMessage
#24 android.os.HandlerThread.run

Related: commit c57f96c92a ("Guard codec buffer access by additional error checks") describes this failure: MediaCodec buffers can be invalidated after codec errors, and writing to one causes a native crash that cannot be avoided from Java. It guards ExoPlayer's input-buffer writes (MediaCodecRenderer through MediaCodecAdapter.useInputBuffer, under the error callback's lock in AsynchronousMediaCodecCallback), and 383e770282 later generalized that to useBuffer for output buffers too. Transformer's DefaultCodec calls MediaCodec directly, so its input-buffer writes have no equivalent guard. We realise a lock alone may not be enough there, since in synchronous mode no error callback arrives before the next MediaCodec call. Could DefaultCodec get a guard, or could the asset loader treat a reclaimed or errored codec's input buffer as invalid before writing into it?

On our side we now cancel sample transcodes when the app goes to the background (where reclaims are most likely), which reduces the exposure but does not remove it.

We have no adb bugreport: both crashes come from Play Console on users' phones.

Media

Not available: the files are the users' own videos, which we never receive.

Bug Report
  • You will email the zip file produced by adb bugreport to [email protected] after filing this issue.
主要言語
Java
スター
3.1k
フォーク
1k
平均マージ
8日 8時間
マージ済み PR(30日)
4

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

androidx/media のほかの issue

androidx/media の issue をすべて見る

似ている issue

Java の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。