Description
We hit a hard native crash (app killed) on iOS when the recorder emits an AudioReady event whose buffer shared_ptr is null. The payload marshalling dereferences it unconditionally, so the process segfaults on the JS thread before any JS handler can run.
AudioEventPayload.h at current main (9d71382):
struct AudioReadyPayload {
std::shared_ptr<AudioBufferHostObject> buffer;
int numFrames;
facebook::jsi::Object toJsiObject(facebook::jsi::Runtime &rt) const {
facebook::jsi::Object obj(rt);
obj.setProperty(rt, "buffer",
facebook::jsi::Object::createFromHostObject(rt, buffer)); // buffer may be null
obj.setProperty(rt, "numFrames", numFrames);
obj.setExternalMemoryPressure(rt, buffer->getSizeInBytes()); // ← SIGSEGV here when null
return obj;
}
};
Crash report (symbolicated, faulting thread = JS thread)
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x000000000000023c
std::shared_ptr<audioapi::AlignedAudioBuffer<8ul>>::operator->() const + 12
audioapi::AudioBufferHostObject::getSizeInBytes() const + 32
audioapi::AudioReadyPayload::toJsiObject(facebook::jsi::Runtime&) const + 220
audioapi::AudioEventHandlerRegistry::buildJsiObject(...) + 48
audioapi::AudioEventHandlerRegistry::invokeHandler(...) + 96
audioapi::AudioEventHandlerRegistry::handleEventOnJSThread(audioapi::AudioEvent, unsigned long long, ...) + 428
facebook::react::CallInvoker::invokeAsync(...)
Full .ips available on request.
Environment
- react-native-audio-api 0.12.2
- react-native 0.81.5, New Architecture
- iPhone 13 (iPhone14,5), iOS 26.5 (23F77)
- Expo SDK 54 dev client
Context / repro characteristics
- App uses a single shared
AudioContext + a single AudioRecorder (onAudioReady → streaming STT), recorder kept running through TTS playback (playAndRecord session).
- The crash fired ~55 min into a session with heavy recorder start/pause/resume cycling — the same sessions where we also intermittently observe the (non-crashing) variant of what looks like the same producer race: a recorder that silently stops delivering frames mid-session, or delivers an event whose JS-side
buffer is undefined.
- We cannot deterministically repro; it appears to be a race between recorder teardown/restart and an in-flight
AudioReady event.
Suggested fix
A null guard in AudioReadyPayload::toJsiObject (skip the emit, or emit with numFrames: 0 and no external memory pressure) would turn a process kill into a droppable event. Guarding at the producer (don't enqueue an AudioReady event with a null buffer) would address the root cause.
Happy to provide the full crash report or test a patch. Thanks for the library!
Description
We hit a hard native crash (app killed) on iOS when the recorder emits an
AudioReadyevent whosebuffershared_ptr is null. The payload marshalling dereferences it unconditionally, so the process segfaults on the JS thread before any JS handler can run.AudioEventPayload.hat currentmain(9d71382):Crash report (symbolicated, faulting thread = JS thread)
Full
.ipsavailable on request.Environment
Context / repro characteristics
AudioContext+ a singleAudioRecorder(onAudioReady→ streaming STT), recorder kept running through TTS playback (playAndRecord session).bufferis undefined.AudioReadyevent.Suggested fix
A null guard in
AudioReadyPayload::toJsiObject(skip the emit, or emit withnumFrames: 0and no external memory pressure) would turn a process kill into a droppable event. Guarding at the producer (don't enqueue anAudioReadyevent with a null buffer) would address the root cause.Happy to provide the full crash report or test a patch. Thanks for the library!