mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Fix TOCTOU race between _try_remove_self_if_above and destructor
The _stop check in _try_remove_self_if_above was outside the _threads_mutex lock, creating a window where a worker thread could read _stop==false, then the destructor could set _stop and snapshot _threads (including that worker), then the worker could acquire the lock, detach itself, and exit. The destructor would then call pthread_join on a detached thread — undefined behavior. Move the _stop check inside the _threads_mutex lock so it is serialized with the destructor's snapshot. Now either the worker holds the lock first (detaches and erases itself before the snapshot) or the destructor sets _stop first (worker sees it and bails out, remaining joinable in the snapshot). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0466d7208f
commit
b9552758fd
1 changed files with 12 additions and 2 deletions
|
|
@ -643,11 +643,21 @@ bool
|
|||
ThreadPool::_try_remove_self_if_above(pthread_t t_,
|
||||
std::size_t min_count_)
|
||||
{
|
||||
mutex_lockguard(_threads_mutex);
|
||||
|
||||
// Check _stop under the lock to close the TOCTOU race with the
|
||||
// destructor. The destructor sets _stop, then acquires
|
||||
// _threads_mutex to snapshot _threads. By checking _stop here
|
||||
// under the same lock, either:
|
||||
// (a) we hold the lock first, see _stop==false, detach and
|
||||
// erase ourselves — the destructor's snapshot won't
|
||||
// include us, so it won't join a detached thread; or
|
||||
// (b) the destructor sets _stop first — we see _stop==true
|
||||
// and bail out, remaining in _threads for the destructor
|
||||
// to join.
|
||||
if(_stop.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
mutex_lockguard(_threads_mutex);
|
||||
|
||||
if(_threads.size() <= min_count_)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue