forked from OSchip/llvm-project
Revert r304285, r304297.
r304285 - [sanitizer] Avoid possible deadlock in child process after fork r304297 - [sanitizer] Trying to fix MAC buildbots after r304285 These changes create deadlock when Tcl calls pthread_create from a pthread_atfork child handler. More info in the original review at https://reviews.llvm.org/D33325 llvm-svn: 304735
This commit is contained in:
parent
4c882d90aa
commit
790838110f
|
@ -47,6 +47,8 @@ static u32 RZSize2Log(u32 rz_size) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AsanAllocator &get_allocator();
|
||||||
|
|
||||||
// The memory chunk allocated from the underlying allocator looks like this:
|
// The memory chunk allocated from the underlying allocator looks like this:
|
||||||
// L L L L L L H H U U U U U U R R
|
// L L L L L L H H U U U U U U R R
|
||||||
// L -- left redzone words (0 or more bytes)
|
// L -- left redzone words (0 or more bytes)
|
||||||
|
@ -717,7 +719,7 @@ struct Allocator {
|
||||||
|
|
||||||
static Allocator instance(LINKER_INITIALIZED);
|
static Allocator instance(LINKER_INITIALIZED);
|
||||||
|
|
||||||
AsanAllocator &get_allocator() {
|
static AsanAllocator &get_allocator() {
|
||||||
return instance.allocator;
|
return instance.allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,5 @@ void asan_mz_force_unlock();
|
||||||
void PrintInternalAllocatorStats();
|
void PrintInternalAllocatorStats();
|
||||||
void AsanSoftRssLimitExceededCallback(bool exceeded);
|
void AsanSoftRssLimitExceededCallback(bool exceeded);
|
||||||
|
|
||||||
AsanAllocator &get_allocator();
|
|
||||||
|
|
||||||
} // namespace __asan
|
} // namespace __asan
|
||||||
#endif // ASAN_ALLOCATOR_H
|
#endif // ASAN_ALLOCATOR_H
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "asan_stats.h"
|
#include "asan_stats.h"
|
||||||
#include "asan_suppressions.h"
|
#include "asan_suppressions.h"
|
||||||
#include "lsan/lsan_common.h"
|
#include "lsan/lsan_common.h"
|
||||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
|
||||||
#include "sanitizer_common/sanitizer_libc.h"
|
#include "sanitizer_common/sanitizer_libc.h"
|
||||||
|
|
||||||
#if SANITIZER_POSIX
|
#if SANITIZER_POSIX
|
||||||
|
@ -705,25 +704,9 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
|
||||||
#endif // ASAN_INTERCEPT___CXA_ATEXIT
|
#endif // ASAN_INTERCEPT___CXA_ATEXIT
|
||||||
|
|
||||||
#if ASAN_INTERCEPT_FORK
|
#if ASAN_INTERCEPT_FORK
|
||||||
static void BeforeFork() {
|
|
||||||
if (SANITIZER_LINUX) {
|
|
||||||
get_allocator().ForceLock();
|
|
||||||
StackDepotLockAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AfterFork() {
|
|
||||||
if (SANITIZER_LINUX) {
|
|
||||||
StackDepotUnlockAll();
|
|
||||||
get_allocator().ForceUnlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERCEPTOR(int, fork, void) {
|
INTERCEPTOR(int, fork, void) {
|
||||||
ENSURE_ASAN_INITED();
|
ENSURE_ASAN_INITED();
|
||||||
BeforeFork();
|
|
||||||
int pid = REAL(fork)();
|
int pid = REAL(fork)();
|
||||||
AfterFork();
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
#endif // ASAN_INTERCEPT_FORK
|
#endif // ASAN_INTERCEPT_FORK
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||||
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
|
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
|
||||||
#include "sanitizer_common/sanitizer_posix.h"
|
#include "sanitizer_common/sanitizer_posix.h"
|
||||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
|
||||||
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
#include "sanitizer_common/sanitizer_tls_get_addr.h"
|
||||||
#include "lsan.h"
|
#include "lsan.h"
|
||||||
#include "lsan_allocator.h"
|
#include "lsan_allocator.h"
|
||||||
|
@ -98,28 +97,6 @@ INTERCEPTOR(void*, valloc, uptr size) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void BeforeFork() {
|
|
||||||
if (SANITIZER_LINUX) {
|
|
||||||
LockAllocator();
|
|
||||||
StackDepotLockAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void AfterFork() {
|
|
||||||
if (SANITIZER_LINUX) {
|
|
||||||
StackDepotUnlockAll();
|
|
||||||
UnlockAllocator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERCEPTOR(int, fork, void) {
|
|
||||||
ENSURE_LSAN_INITED;
|
|
||||||
BeforeFork();
|
|
||||||
int pid = REAL(fork)();
|
|
||||||
AfterFork();
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SANITIZER_INTERCEPT_MEMALIGN
|
#if SANITIZER_INTERCEPT_MEMALIGN
|
||||||
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
|
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
|
||||||
ENSURE_LSAN_INITED;
|
ENSURE_LSAN_INITED;
|
||||||
|
@ -359,7 +336,6 @@ void InitializeInterceptors() {
|
||||||
LSAN_MAYBE_INTERCEPT_MALLOPT;
|
LSAN_MAYBE_INTERCEPT_MALLOPT;
|
||||||
INTERCEPT_FUNCTION(pthread_create);
|
INTERCEPT_FUNCTION(pthread_create);
|
||||||
INTERCEPT_FUNCTION(pthread_join);
|
INTERCEPT_FUNCTION(pthread_join);
|
||||||
INTERCEPT_FUNCTION(fork);
|
|
||||||
|
|
||||||
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
|
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
|
||||||
Report("LeakSanitizer: failed to create thread key.\n");
|
Report("LeakSanitizer: failed to create thread key.\n");
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
// MemorySanitizer allocator.
|
// MemorySanitizer allocator.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_allocator.h"
|
||||||
|
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||||
#include "msan.h"
|
#include "msan.h"
|
||||||
#include "msan_allocator.h"
|
#include "msan_allocator.h"
|
||||||
#include "msan_origin.h"
|
#include "msan_origin.h"
|
||||||
|
@ -20,12 +22,102 @@
|
||||||
|
|
||||||
namespace __msan {
|
namespace __msan {
|
||||||
|
|
||||||
|
struct Metadata {
|
||||||
|
uptr requested_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MsanMapUnmapCallback {
|
||||||
|
void OnMap(uptr p, uptr size) const {}
|
||||||
|
void OnUnmap(uptr p, uptr size) const {
|
||||||
|
__msan_unpoison((void *)p, size);
|
||||||
|
|
||||||
|
// We are about to unmap a chunk of user memory.
|
||||||
|
// Mark the corresponding shadow memory as not needed.
|
||||||
|
uptr shadow_p = MEM_TO_SHADOW(p);
|
||||||
|
ReleaseMemoryPagesToOS(shadow_p, shadow_p + size);
|
||||||
|
if (__msan_get_track_origins()) {
|
||||||
|
uptr origin_p = MEM_TO_ORIGIN(p);
|
||||||
|
ReleaseMemoryPagesToOS(origin_p, origin_p + size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__mips64)
|
||||||
|
static const uptr kMaxAllowedMallocSize = 2UL << 30;
|
||||||
|
static const uptr kRegionSizeLog = 20;
|
||||||
|
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||||
|
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||||
|
|
||||||
|
struct AP32 {
|
||||||
|
static const uptr kSpaceBeg = 0;
|
||||||
|
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
||||||
|
static const uptr kMetadataSize = sizeof(Metadata);
|
||||||
|
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
|
||||||
|
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
|
||||||
|
typedef __msan::ByteMap ByteMap;
|
||||||
|
typedef MsanMapUnmapCallback MapUnmapCallback;
|
||||||
|
static const uptr kFlags = 0;
|
||||||
|
};
|
||||||
|
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)
|
||||||
|
static const uptr kAllocatorSpace = 0x700000000000ULL;
|
||||||
|
#else
|
||||||
|
static const uptr kAllocatorSpace = 0x600000000000ULL;
|
||||||
|
#endif
|
||||||
|
static const uptr kMaxAllowedMallocSize = 8UL << 30;
|
||||||
|
|
||||||
|
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
||||||
|
static const uptr kSpaceBeg = kAllocatorSpace;
|
||||||
|
static const uptr kSpaceSize = 0x40000000000; // 4T.
|
||||||
|
static const uptr kMetadataSize = sizeof(Metadata);
|
||||||
|
typedef DefaultSizeClassMap SizeClassMap;
|
||||||
|
typedef MsanMapUnmapCallback MapUnmapCallback;
|
||||||
|
static const uptr kFlags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||||
|
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
||||||
|
|
||||||
|
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
||||||
|
static const uptr kSpaceBeg = 0x300000000000;
|
||||||
|
static const uptr kSpaceSize = 0x020000000000; // 2T.
|
||||||
|
static const uptr kMetadataSize = sizeof(Metadata);
|
||||||
|
typedef DefaultSizeClassMap SizeClassMap;
|
||||||
|
typedef MsanMapUnmapCallback MapUnmapCallback;
|
||||||
|
static const uptr kFlags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
||||||
|
static const uptr kRegionSizeLog = 20;
|
||||||
|
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
||||||
|
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
||||||
|
|
||||||
|
struct AP32 {
|
||||||
|
static const uptr kSpaceBeg = 0;
|
||||||
|
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
||||||
|
static const uptr kMetadataSize = sizeof(Metadata);
|
||||||
|
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
|
||||||
|
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
|
||||||
|
typedef __msan::ByteMap ByteMap;
|
||||||
|
typedef MsanMapUnmapCallback MapUnmapCallback;
|
||||||
|
static const uptr kFlags = 0;
|
||||||
|
};
|
||||||
|
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
||||||
|
#endif
|
||||||
|
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
||||||
|
typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
|
||||||
|
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
||||||
|
SecondaryAllocator> Allocator;
|
||||||
|
|
||||||
static Allocator allocator;
|
static Allocator allocator;
|
||||||
static AllocatorCache fallback_allocator_cache;
|
static AllocatorCache fallback_allocator_cache;
|
||||||
static SpinMutex fallback_mutex;
|
static SpinMutex fallback_mutex;
|
||||||
|
|
||||||
Allocator &get_allocator() { return allocator; }
|
|
||||||
|
|
||||||
void MsanAllocatorInit() {
|
void MsanAllocatorInit() {
|
||||||
allocator.Init(
|
allocator.Init(
|
||||||
common_flags()->allocator_may_return_null,
|
common_flags()->allocator_may_return_null,
|
||||||
|
|
|
@ -15,106 +15,9 @@
|
||||||
#define MSAN_ALLOCATOR_H
|
#define MSAN_ALLOCATOR_H
|
||||||
|
|
||||||
#include "sanitizer_common/sanitizer_common.h"
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
#include "sanitizer_common/sanitizer_allocator.h"
|
|
||||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
|
||||||
|
|
||||||
namespace __msan {
|
namespace __msan {
|
||||||
|
|
||||||
struct Metadata {
|
|
||||||
uptr requested_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MsanMapUnmapCallback {
|
|
||||||
void OnMap(uptr p, uptr size) const {}
|
|
||||||
void OnUnmap(uptr p, uptr size) const {
|
|
||||||
__msan_unpoison((void *)p, size);
|
|
||||||
|
|
||||||
// We are about to unmap a chunk of user memory.
|
|
||||||
// Mark the corresponding shadow memory as not needed.
|
|
||||||
uptr shadow_p = MEM_TO_SHADOW(p);
|
|
||||||
ReleaseMemoryPagesToOS(shadow_p, shadow_p + size);
|
|
||||||
if (__msan_get_track_origins()) {
|
|
||||||
uptr origin_p = MEM_TO_ORIGIN(p);
|
|
||||||
ReleaseMemoryPagesToOS(origin_p, origin_p + size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(__mips64)
|
|
||||||
static const uptr kMaxAllowedMallocSize = 2UL << 30;
|
|
||||||
static const uptr kRegionSizeLog = 20;
|
|
||||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
|
||||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
|
||||||
|
|
||||||
struct AP32 {
|
|
||||||
static const uptr kSpaceBeg = 0;
|
|
||||||
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
|
||||||
static const uptr kMetadataSize = sizeof(Metadata);
|
|
||||||
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
|
|
||||||
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
|
|
||||||
typedef __msan::ByteMap ByteMap;
|
|
||||||
typedef MsanMapUnmapCallback MapUnmapCallback;
|
|
||||||
static const uptr kFlags = 0;
|
|
||||||
};
|
|
||||||
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
#if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)
|
|
||||||
static const uptr kAllocatorSpace = 0x700000000000ULL;
|
|
||||||
#else
|
|
||||||
static const uptr kAllocatorSpace = 0x600000000000ULL;
|
|
||||||
#endif
|
|
||||||
static const uptr kMaxAllowedMallocSize = 8UL << 30;
|
|
||||||
|
|
||||||
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
|
||||||
static const uptr kSpaceBeg = kAllocatorSpace;
|
|
||||||
static const uptr kSpaceSize = 0x40000000000; // 4T.
|
|
||||||
static const uptr kMetadataSize = sizeof(Metadata);
|
|
||||||
typedef DefaultSizeClassMap SizeClassMap;
|
|
||||||
typedef MsanMapUnmapCallback MapUnmapCallback;
|
|
||||||
static const uptr kFlags = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
|
||||||
|
|
||||||
#elif defined(__powerpc64__)
|
|
||||||
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
|
||||||
|
|
||||||
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
|
||||||
static const uptr kSpaceBeg = 0x300000000000;
|
|
||||||
static const uptr kSpaceSize = 0x020000000000; // 2T.
|
|
||||||
static const uptr kMetadataSize = sizeof(Metadata);
|
|
||||||
typedef DefaultSizeClassMap SizeClassMap;
|
|
||||||
typedef MsanMapUnmapCallback MapUnmapCallback;
|
|
||||||
static const uptr kFlags = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
|
||||||
#elif defined(__aarch64__)
|
|
||||||
static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
|
|
||||||
static const uptr kRegionSizeLog = 20;
|
|
||||||
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
|
||||||
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
|
||||||
|
|
||||||
struct AP32 {
|
|
||||||
static const uptr kSpaceBeg = 0;
|
|
||||||
static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
|
|
||||||
static const uptr kMetadataSize = sizeof(Metadata);
|
|
||||||
typedef __sanitizer::CompactSizeClassMap SizeClassMap;
|
|
||||||
static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
|
|
||||||
typedef __msan::ByteMap ByteMap;
|
|
||||||
typedef MsanMapUnmapCallback MapUnmapCallback;
|
|
||||||
static const uptr kFlags = 0;
|
|
||||||
};
|
|
||||||
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
|
||||||
#endif
|
|
||||||
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
|
||||||
typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
|
|
||||||
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
|
||||||
SecondaryAllocator> Allocator;
|
|
||||||
|
|
||||||
|
|
||||||
Allocator &get_allocator();
|
|
||||||
|
|
||||||
struct MsanThreadLocalMallocStorage {
|
struct MsanThreadLocalMallocStorage {
|
||||||
uptr quarantine_cache[16];
|
uptr quarantine_cache[16];
|
||||||
// Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
|
// Allocator cache contains atomic_uint64_t which must be 8-byte aligned.
|
||||||
|
|
|
@ -1201,7 +1201,6 @@ INTERCEPTOR(void *, shmat, int shmid, const void *shmaddr, int shmflg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void BeforeFork() {
|
static void BeforeFork() {
|
||||||
get_allocator().ForceLock();
|
|
||||||
StackDepotLockAll();
|
StackDepotLockAll();
|
||||||
ChainedOriginDepotLockAll();
|
ChainedOriginDepotLockAll();
|
||||||
}
|
}
|
||||||
|
@ -1209,7 +1208,6 @@ static void BeforeFork() {
|
||||||
static void AfterFork() {
|
static void AfterFork() {
|
||||||
ChainedOriginDepotUnlockAll();
|
ChainedOriginDepotUnlockAll();
|
||||||
StackDepotUnlockAll();
|
StackDepotUnlockAll();
|
||||||
get_allocator().ForceUnlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERCEPTOR(int, fork, void) {
|
INTERCEPTOR(int, fork, void) {
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
// https://github.com/google/sanitizers/issues/774
|
|
||||||
// Test that sanitizer allocator is fork-safe.
|
|
||||||
// Run a number of threads that perform memory allocation/deallocation, then fork
|
|
||||||
// and verify that malloc/free do not deadlock in the child process.
|
|
||||||
|
|
||||||
// RUN: %clangxx -std=c++11 -O0 %s -o %t
|
|
||||||
// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t 2>&1 | FileCheck %s
|
|
||||||
|
|
||||||
// Fun fact: if test output is redirected to a file (as opposed to
|
|
||||||
// being piped directly to FileCheck), we may lose some "done"s due to
|
|
||||||
// a kernel bug:
|
|
||||||
// https://lkml.org/lkml/2014/2/17/324
|
|
||||||
|
|
||||||
// UNSUPPORTED: tsan
|
|
||||||
|
|
||||||
// Flaky on PPC64.
|
|
||||||
// UNSUPPORTED: powerpc64-target-arch
|
|
||||||
// UNSUPPORTED: powerpc64le-target-arch
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
int done;
|
|
||||||
|
|
||||||
void *worker(void *arg) {
|
|
||||||
while (true) {
|
|
||||||
void *p = malloc(4);
|
|
||||||
if (__atomic_load_n(&done, __ATOMIC_RELAXED))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run through malloc/free in the child process.
|
|
||||||
// This can deadlock on allocator cache refilling.
|
|
||||||
void child() {
|
|
||||||
for (int i = 0; i < 10000; ++i) {
|
|
||||||
void *p = malloc(4);
|
|
||||||
}
|
|
||||||
write(2, "done\n", 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test() {
|
|
||||||
const int kThreads = 10;
|
|
||||||
pthread_t t[kThreads];
|
|
||||||
for (int i = 0; i < kThreads; ++i)
|
|
||||||
pthread_create(&t[i], NULL, worker, (void*)(long)i);
|
|
||||||
usleep(100000);
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid) {
|
|
||||||
// parent
|
|
||||||
__atomic_store_n(&done, 1, __ATOMIC_RELAXED);
|
|
||||||
pid_t p;
|
|
||||||
while ((p = wait(NULL)) == -1) { }
|
|
||||||
} else {
|
|
||||||
// child
|
|
||||||
child();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
const int kChildren = 30;
|
|
||||||
for (int i = 0; i < kChildren; ++i) {
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid) {
|
|
||||||
// parent
|
|
||||||
} else {
|
|
||||||
test();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < kChildren; ++i) {
|
|
||||||
pid_t p;
|
|
||||||
while ((p = wait(NULL)) == -1) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expect 30 (== kChildren) "done" messages.
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
||||||
// CHECK: done
|
|
Loading…
Reference in New Issue