-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[msan] Make origin tracking fork-safe.
Chained origins make plain memory stores async-signal-unsafe. We already disable it inside signal handlers. This change grabs all origin-related locks before fork() and releases them after fork() to avoid a deadlock in the child process. llvm-svn: 217140
- Loading branch information
Showing
7 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Test that chained origins are fork-safe. | ||
// Run a number of threads that create new chained origins, then fork | ||
// and verify that origin reads do not deadlock in the child process. | ||
|
||
// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -m64 -O3 %s -o %t | ||
// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& 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 | ||
|
||
|
||
#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> | ||
#include <atomic> | ||
|
||
#include <sanitizer/msan_interface.h> | ||
|
||
std::atomic<bool> done; | ||
|
||
void copy_uninit_thread2() { | ||
volatile int x; | ||
volatile int v; | ||
while (true) { | ||
v = x; | ||
x = v; | ||
if (done.load()) | ||
return; | ||
} | ||
} | ||
|
||
void copy_uninit_thread1(int level) { | ||
if (!level) | ||
copy_uninit_thread2(); | ||
else | ||
copy_uninit_thread1(level - 1); | ||
} | ||
|
||
void *copy_uninit_thread(void *id) { | ||
copy_uninit_thread1((long)id); | ||
return 0; | ||
} | ||
|
||
// Run through stackdepot in the child process. | ||
// If any of the hash table cells are locked, this may deadlock. | ||
void child() { | ||
volatile int x; | ||
volatile int v; | ||
for (int i = 0; i < 10000; ++i) { | ||
v = x; | ||
x = v; | ||
} | ||
write(2, "done\n", 5); | ||
} | ||
|
||
void test() { | ||
done.store(false); | ||
const int kThreads = 10; | ||
pthread_t t[kThreads]; | ||
for (int i = 0; i < kThreads; ++i) | ||
pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i); | ||
usleep(100000); | ||
pid_t pid = fork(); | ||
if (pid) { | ||
// parent | ||
done.store(true); | ||
usleep(1000000); | ||
kill(pid, SIGKILL); | ||
} else { | ||
// child | ||
child(); | ||
} | ||
} | ||
|
||
int main() { | ||
const int kChildren = 20; | ||
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 20 (== 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 |