From 1d0bba8c1d9d5168d07c1c51137849dd3aaf11bd Mon Sep 17 00:00:00 2001 From: Roy Arad Date: Tue, 28 Oct 2025 17:13:10 +0200 Subject: [PATCH 1/2] Fix use-after-free bug in registry_watcher --- include/wil/registry.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/wil/registry.h b/include/wil/registry.h index ac37f62b8..292fc088d 100644 --- a/include/wil/registry.h +++ b/include/wil/registry.h @@ -3123,6 +3123,8 @@ namespace details if (0 == ::InterlockedDecrement(&m_refCount)) { lock.reset(); // leave the lock before deleting it. + // Make sure callbacks are not running in parallel to destruction. + m_threadPoolWait.reset(); delete this; } } @@ -3139,7 +3141,7 @@ namespace details delete this; // Sleep(1); // Enable for testing to find use after free bugs. } - else if (rearm) + else if (rearm && m_threadPoolWait.is_valid()) { ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); } From 4c8cec25abf10b81dec82161afec7a4c9784c0de Mon Sep 17 00:00:00 2001 From: royar13 Date: Wed, 29 Oct 2025 14:07:46 +0200 Subject: [PATCH 2/2] Avoid conflict over m_threadPoolWait access between Release and ReleaseFromCallback --- include/wil/registry.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/wil/registry.h b/include/wil/registry.h index 292fc088d..68600ccef 100644 --- a/include/wil/registry.h +++ b/include/wil/registry.h @@ -3132,7 +3132,8 @@ namespace details void ReleaseFromCallback(bool rearm) { auto lock = m_lock.lock_exclusive(); - if (0 == ::InterlockedDecrement(&m_refCount)) + auto refCount = ::InterlockedDecrement(&m_refCount); + if (0 == refCount) { // Destroy the thread pool wait now to avoid the wait that would occur in the // destructor. That wait would cause a deadlock since we are doing this from the callback. @@ -3141,7 +3142,7 @@ namespace details delete this; // Sleep(1); // Enable for testing to find use after free bugs. } - else if (rearm && m_threadPoolWait.is_valid()) + else if (rearm && refCount > 0) { ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); }