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

Aperta
#3,537 1 commento 0 reazioni 1 assegnatario Vedi su GitHub

I maintainer di solito rispondono entro 4 giorni

@droid-girl ci sta già lavorando.

Dal 11/11/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

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.
Lingua principale
Java
Stelle
3.1k
Fork
1k
Merge medio
8g 8h
PR unite (30g)
4

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di androidx/media

Tutte le issue di androidx/media

Issue simili

Altre issue su Java

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.