Skip to main content
New Participant
July 15, 2026
Question

SIGSEGV in libaudioutils.so on AudioRecord thread — PTC v81 regression, reproducible

Summary

On Quest 3 running the Public Test Channel build (v81 / reported as 2.6 in Settings), any app that opens an audio input stream can be killed by a native crash in the system audio stack. The fault is SIGSEGV / SEGV_ACCERR inside memcpy_to_i16_from_i32 in /system/lib64/libaudioutils.so, called from android::AudioRecord::processAudioBuffer().

This is not app code. The entire backtrace is system libraries. The crashing thread is AudioRecord, which the platform owns.

I hit this in Supernatural (in.with.flow.Swords), but nothing in the trace is specific to that app, and I'd expect any mic-using app on this build to be affected.

Environment

  • Device: Meta Quest 3 (oculus/eureka/eureka)
  • Build fingerprint: oculus/eureka/eureka:14/UP1A.231005.007.A1/52345320022000520:user/abl_signing_keys:release,amss_signing_keys:release,release-keys
  • Android version: 14
  • Channel: Public Test Channel (v81, shown as 2.6)
  • Audio hardware: Built-in headset speakers and microphone only. No Bluetooth audio device. No USB audio, no external accessories.
  • App: Supernatural, package in.with.flow.Swords
  • Onset: Approximately 2026-07-08

Symptom

The app terminates and the user is dropped to the Quest home menu. No error dialog, no "app has stopped" message.

Timing is specific and consistent:

  • Never during a song. The capture stream is up and steady, and it is stable for the entire duration.
  • Between songs, at transitions to warm-up or cool-down, and on entering the group lobby — i.e. exactly the points where the app tears down and re-establishes the audio input stream.

Root cause evidence

Two tombstones captured on separate crashes, ~15 minutes apart. They are effectively identical.

Both faulted at the same instruction with the same register state:

                        Crash 1 (07:12:14)      Crash 2 (07:27:17)
  Signal                SIGSEGV, SEGV_ACCERR    SIGSEGV, SEGV_ACCERR
  Fault addr            0x781df0a000            0x7823740000
  Thread                AudioRecord             AudioRecord
  pc                    0x78c17c8900            0x78c17c8900
  x2 / x4 / x6 / x10    0xf0                    0xf0
  x3                    3                       3
  Process uptime        2653s                   3556s

Both fault addresses are page-aligned (...000), consistent with a read running off the end of a buffer into a guard page.

The copy parameters are identical across both runs: 240 bytes (0xf0), same value in x3. This is not a race with variable timing — it is the same undersized-buffer calculation producing the same overrun each time. The only difference between the two crashes is the heap address the buffer happened to land at.

The faulting function converts a capture buffer from 32-bit to 16-bit samples. That the 32-bit input path is in use at all is worth noting — it is not the common configuration for built-in mic capture, and may be relevant to why the size calculation is wrong.

Backtrace (identical in both tombstones)

#00 pc 0000000000043900  /system/lib64/libaudioutils.so (memcpy_to_i16_from_i32+160)
    (BuildId: bced043301f18da9ca68fe1a48f771f8)
#01 pc 0000000000068098  /system/lib64/libaudioclient.so (android::AudioRecord::processAudioBuffer()+1592)
    (BuildId: cdd76a869040743d49b049e724a1da40)
#02 pc 0000000000067760  /system/lib64/libaudioclient.so (android::AudioRecord::AudioRecordThread::threadLoop()+272)
    (BuildId: cdd76a869040743d49b049e724a1da40)
#03 pc 0000000000010a00  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+320)
    (BuildId: 4654974f2f7e1bb338118c84396e44a0)
#04 pc 00000000000e6d60  /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)
    (BuildId: 789ec1df193cf5c4d110adc4a1974d3e)
#05 pc 00000000000fe0ac  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+204)
    (BuildId: a53e2446c160ae0666e920bc84a1b66e)
#06 pc 0000000000095f70  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
    (BuildId: a53e2446c160ae0666e920bc84a1b66e)

Full tombstone header from crash 2:

pid: 20550, tid: 21294, name: AudioRecord  >>> in.with.flow.Swords <<<
uid: 10092
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x0000007823740000
Killed-By-AM: No
OOM-Score-Adj: 0
State: TOP
Foreground: Yes
Rss-Kb: 1447524
Rss-Hwm-Kb: 1447524
Vm-Swap-Kb: 0

Causes ruled out

Each of these was tested and eliminated, not assumed:

  • Not an OOM kill. Killed-By-AM: No, Killed: No, OOM-Score-Adj: 0, State: TOP, Foreground: Yes. RSS at ~1.4 GB with 0 swap — unremarkable. The process faulted on its own; the OS was not reclaiming it.
  • Not app code. Zero frames in the app's own native libraries. Every frame is /system/lib64 or the runtime APEX.
  • Not Bluetooth. No Bluetooth or external audio device involved at any point. Built-in mic and speakers only.
  • Not mic contention with another app. An earlier crash was captured while a separate voice call was running. The crash reproduced identically with that call fully closed (not muted), same registers, same trace.
  • Not a corrupt install. App was uninstalled and reinstalled; headset fully power-cycled multiple times. No change.
  • Not a network or backend issue. No network frames anywhere in the stack.

Isolating variable: PTC build

I am on the Public Test Channel (2.6). Friends playing the same app in the same sessions on the stable channel (2.5) do not experience this. Same app version, same activity, same lobby. The differing component — libaudioutils.so — ships with the OS build.

Workaround

Revoking the app's microphone permission eliminates the crash entirely:

adb shell pm revoke in.with.flow.Swords android.permission.RECORD_AUDIO

With the permission revoked, AudioRecord is never constructed, processAudioBuffer() is never called, and the crash cannot occur. Verified across a complete workout including all song transitions and lobby entry — zero crashes, and adb logcat -b crash returned empty.

This confirms the diagnosis but is not an acceptable fix for users: it disables voice chat, which for group workouts is the primary reason to use the app.

Note that in-app mute does not work as a workaround. Mute operates above the capture layer; the stream stays open and processAudioBuffer() keeps running.

Reproduction steps

  1. Quest 3 on PTC v81 (2.6), built-in audio only.
  2. Launch an app that opens a microphone input stream (observed in Supernatural).
  3. Play through content that causes the app to stop and restart the input stream — in Supernatural, transition between songs, into warm-up/cool-down, or enter the group lobby.
  4. App terminates to home menu. Capture with adb logcat -b crash.

Observed twice within a 15-minute window; onset roughly one week ago, consistent with a recent PTC push.

Impact

The crash is in a shared system audio library on a code path used by any app doing 32-bit-to-16-bit capture conversion. The scope is therefore likely broader than one app. Supernatural is a useful reproduction case because it cycles the input stream frequently and predictably, but the defect is in the platform.

Suggestions for investigation

  • Whether memcpy_to_i16_from_i32 or its callers in AudioRecord::processAudioBuffer() changed between v80 and v81.
  • Whether the buffer size calculation for the 32→16-bit input conversion path accounts correctly for frame size on this build.
  • A supported rollback path for PTC users. Opting out of the channel does not roll the build back; the only route to a known-good build is a factory reset, which is a heavy remedy for a beta regression that breaks all microphone use.