Skip to content

[iOS] Hard crash (SIGSEGV): AudioReadyPayload::toJsiObject dereferences a null buffer — no null check at HEAD #1109

Description

@Wladefant

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions