From 82e7980ec901119bc13323b7d1f0b5f878f305aa Mon Sep 17 00:00:00 2001 From: "Antonio S. Musumeci" Date: Thu, 9 Apr 2026 21:04:37 -0400 Subject: [PATCH] Fix TOCTOU race in _maybe_grow_on_pressure Multiple concurrent enqueue_work_autoscale callers could all pass the cooldown check and each add a thread, overshooting max_threads and bypassing the intended rate limit. Use compare_exchange_strong on _last_scale_time_usecs so only one caller wins the cooldown window. Then hold _scaling_mutex for the thread-count check and _add_thread_locked call so the grow is atomic with respect to other scaling operations (monitor, set_threads). Co-Authored-By: Claude Opus 4.6 (1M context) --- vendored/libfuse/include/thread_pool.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/vendored/libfuse/include/thread_pool.hpp b/vendored/libfuse/include/thread_pool.hpp index e7ef87fb..32fd77a7 100644 --- a/vendored/libfuse/include/thread_pool.hpp +++ b/vendored/libfuse/include/thread_pool.hpp @@ -608,6 +608,15 @@ ThreadPool::_maybe_grow_on_pressure() if((now - last) < (std::uint64_t)_scaling_config.cooldown_usecs) return; + // CAS to claim the cooldown window — only one caller wins. + if(!_last_scale_time_usecs.compare_exchange_strong(last,now, + std::memory_order_relaxed)) + return; + + // Hold _scaling_mutex so the thread-count check and add are atomic + // with respect to other scaling operations. + mutex_lockguard(_scaling_mutex); + std::size_t count; { mutex_lockguard(_threads_mutex); @@ -616,8 +625,7 @@ ThreadPool::_maybe_grow_on_pressure() if(count < _scaling_config.max_threads) { - add_thread(); - _last_scale_time_usecs.store(now,std::memory_order_relaxed); + _add_thread_locked({}); syslog(LOG_DEBUG, "threadpool (%s): fast-path grow to %zu threads (queue full)", _name.c_str(),