Skip to content

OpenAL use-after-free in OpenALAudioManager::update() (dangling shared AudioEventRTS) — SIGSEGV on macOS #149

@yasser159

Description

@yasser159

Summary

OpenALAudioManager::update() can dereference a dangling AudioEventRTS, causing a SIGSEGV ~30–60s into a session (reproducible on Apple Silicon / macOS 26, weekly-2026-05-29 ZH build). Most visible when launching with -noaudio, but the underlying lifetime bug is independent of the audio-on state.

Crash (symbolicated, arm64)

AsciiString::str()
operator==(AsciiString const&, AsciiString const&)
AudioEventRTS::getAudioEventInfo() const
OpenALAudioManager::doesViolateLimit(AudioEventRTS*) / adjustPlayingVolume(PlayingAudio*)
OpenALAudioManager::processPlayingList()  /  SoundManager::canPlayNow()
OpenALAudioManager::update()

Faulting read is on a freed string (the bad address is the ASCII bytes of an event name read as a pointer).

Root cause

releasePlayingAudio() frees the event via releaseAudioEventRTS(release->m_audioEventRTS) when m_cleanupAudioEventRTS is set. When a single AudioEventRTS is shared (e.g. across Attack/Sound/Decay portions or 2D/3D request+playing entries), freeing it through one PlayingAudio leaves other PlayingAudio entries with a dangling m_audioEventRTS. The existing if (!m_audioEventRTS) guards don't catch a freed-but-non-null pointer, so the next frame's getAudioEventInfo() reads freed memory.

Mitigation (verified — stops the crash)

Skip list processing in update() when all audio affects are off (the common -noaudio path). Verified: rebuilt & ran with no audio crash.

void OpenALAudioManager::update() {
    AudioManager::update();
    if (!isOn(AudioAffect_Music) && !isOn(AudioAffect_Sound)
            && !isOn(AudioAffect_Sound3D) && !isOn(AudioAffect_Speech)) {
        return;
    }
    setDeviceListenerPosition();
    processRequestList(); processPlayingList(); processFadingList(); processStoppedList();
}

This is a mitigation, not the root fix — the proper fix is ownership/lifetime of the shared AudioEventRTS (ensure only the last reference frees it, or null out sibling references on free). Patch attached. Happy to open a PR if useful.

Environment: M4 Pro, macOS 26.x, GeneralsXZH weekly-2026-05-29, retail 1.04 data.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions