From aa0bb9d1731c13c180bd721ef0b3c6eb9363aa3f Mon Sep 17 00:00:00 2001 From: OmikronApex Date: Thu, 16 Jul 2026 22:54:22 +0200 Subject: [PATCH] fix(audio): fail runDeviceLifecycleOp when the MessageManager is gone A null MessageManager (pre-init or mid-shutdown) previously fell through to inline execution on the caller's thread while reporting success - exactly the unserialised device teardown this helper prevents. Return false instead, per the documented unavailable/timeout contract. Addresses CodeRabbit review on #113. Co-Authored-By: Claude Fable 5 --- src/audio/addon/AddonContext.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/audio/addon/AddonContext.h b/src/audio/addon/AddonContext.h index 882c05d..fec85f7 100644 --- a/src/audio/addon/AddonContext.h +++ b/src/audio/addon/AddonContext.h @@ -84,9 +84,15 @@ template inline bool runDeviceLifecycleOp(Func&& func) { #if JUCE_WINDOWS - if (auto* mm = juce::MessageManager::getInstanceWithoutCreating()) - if (!mm->isThisTheMessageThread()) - return dispatchOnMessageThread(std::forward(func)); + // No MessageManager means the pump is gone (pre-init or mid-shutdown): + // report failure instead of running the mutation unserialised on the + // caller's thread — that would reintroduce the race this helper exists + // to prevent (CodeRabbit #113 review). + auto* mm = juce::MessageManager::getInstanceWithoutCreating(); + if (mm == nullptr) + return false; + if (!mm->isThisTheMessageThread()) + return dispatchOnMessageThread(std::forward(func)); #endif func(); return true;