musl: allocator: Avoid deadlock in pthread_atfork
Musl 1.2.3 and before call malloc() in pthread_atfork(),
which may result in a deadlock:
PartitionRoot::EnableThreadCacheIfSupported()
::partition_alloc::internal::ScopedGuard guard{lock_};
ThreadCache::Create(this);
ThreadCache::ThreadCache()
PlatformThread::CurrentId()
InitAtFork::InitAtFork()
pthread_atfork()
malloc()
ShimMalloc()
PartitionAllocFunctionsInternal::Malloc()
PartitionRoot::AllocInternal()
PartitionRoot::AllocInternalNoHooks()
PartitionRoot::RawAlloc()
::partition_alloc::internal::ScopedGuard guard{internal::PartitionRootLock(this)};
This commit is contained in:
@ -32,6 +32,10 @@
|
||||
#include <zircon/process.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MUSL__)
|
||||
#include "partition_alloc/shim/allocator_shim.h"
|
||||
#endif
|
||||
|
||||
namespace partition_alloc::internal::base {
|
||||
|
||||
#if PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
|
||||
@ -63,7 +67,22 @@ thread_local bool g_is_main_thread = true;
|
||||
class InitAtFork {
|
||||
public:
|
||||
InitAtFork() {
|
||||
#if defined(__MUSL__)
|
||||
allocator_shim::AllocatorDispatch d =
|
||||
*allocator_shim::GetAllocatorDispatchChainHeadForTesting();
|
||||
d.alloc_function = +[](size_t size, void*) -> void* {
|
||||
// The size of the scratch fits struct atfork_funcs in Musl pthread_atfork.c.
|
||||
static char scratch[5 * sizeof(void*)];
|
||||
return size != sizeof(scratch) ? nullptr : scratch;
|
||||
};
|
||||
allocator_shim::InsertAllocatorDispatch(&d);
|
||||
#endif
|
||||
|
||||
pthread_atfork(nullptr, nullptr, internal::InvalidateTidCache);
|
||||
|
||||
#if defined(__MUSL__)
|
||||
allocator_shim::RemoveAllocatorDispatchForTesting(&d);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -55,6 +55,10 @@
|
||||
#include <pthread.h>
|
||||
#endif // PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
|
||||
|
||||
#if defined(__MUSL__)
|
||||
#include "partition_alloc/shim/allocator_shim.h"
|
||||
#endif
|
||||
|
||||
namespace partition_alloc::internal {
|
||||
|
||||
#if PA_BUILDFLAG(RECORD_ALLOC_INFO)
|
||||
@ -322,9 +326,25 @@ void PartitionAllocMallocInitOnce() {
|
||||
// However, no perfect solution really exists to make threads + fork()
|
||||
// cooperate, but deadlocks are real (and fork() is used in DEATH_TEST()s),
|
||||
// and other malloc() implementations use the same techniques.
|
||||
|
||||
#if defined(__MUSL__)
|
||||
allocator_shim::AllocatorDispatch d =
|
||||
*allocator_shim::GetAllocatorDispatchChainHeadForTesting();
|
||||
d.alloc_function = +[](size_t size, void*) -> void* {
|
||||
// The size of the scratch fits struct atfork_funcs in Musl pthread_atfork.c.
|
||||
static char scratch[5 * sizeof(void*)];
|
||||
return size != sizeof(scratch) ? nullptr : scratch;
|
||||
};
|
||||
allocator_shim::InsertAllocatorDispatch(&d);
|
||||
#endif
|
||||
|
||||
int err =
|
||||
pthread_atfork(BeforeForkInParent, AfterForkInParent, AfterForkInChild);
|
||||
PA_CHECK(err == 0);
|
||||
|
||||
#if defined(__MUSL__)
|
||||
allocator_shim::RemoveAllocatorDispatchForTesting(&d);
|
||||
#endif
|
||||
#endif // PA_BUILDFLAG(IS_LINUX) || PA_BUILDFLAG(IS_CHROMEOS)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user