Skip to content

WasapiDevice::m_impl read/delete race in framesPlayed() (master clock) #80

Description

@duremovich

From the 2026-07-03 comprehensive review.

WasapiDevice::framesPlayed() is the master clock (via AudioRateSource::now(), sampled on editor and show threads — the timeline genlocks to it per Engine.cpp:704 setAudioRateSource). It reads plain Impl* m_impl (WasapiDevice.hpp:38) and dereferences impl->clock->GetPosition (WasapiDevice.cpp:264-267). During stop(), the render thread Reset()s the COM objects, deletes impl, and nulls m_impl (:235-241) with no synchronization against a concurrent reader.

Failure: device stop / app shutdown / default-device change while the editor or show thread samples the clock → use-after-free on the master clock path.

Fix: make m_impl std::atomic<Impl*>, load-acquire once per call; ensure stop() orders the null-store before the delete (or defer the delete until readers cannot hold the pointer). Initial publish via the promise/future is fine.

Related, lower priority: no recovery on AUDCLNT_E_DEVICE_INVALIDATED (:209, :217) — unplugging headphones silently kills audio until restart; a media server should re-acquire the default endpoint.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtier:coreLives in core (GPLv3, in-repo); always free, fully featured

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions