mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-11-28 01:14:20 +01:00
Fix race in VerifyStackReadWithMultipleThreads
Patch by Chris Dearman <chris@mips.com> R=ted at http://breakpad.appspot.com/377002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@959 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
e8dbecb42c
commit
e6e778f635
@ -51,7 +51,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *thread_function(void *data) {
|
void *thread_function(void *data) {
|
||||||
|
int pipefd = *static_cast<int *>(data);
|
||||||
volatile pid_t thread_id = syscall(__NR_gettid);
|
volatile pid_t thread_id = syscall(__NR_gettid);
|
||||||
|
// Signal parent that a thread has started.
|
||||||
|
uint8_t byte = 1;
|
||||||
|
if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) {
|
||||||
|
perror("ERROR: parent notification failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
|
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
|
||||||
while (true)
|
while (true)
|
||||||
asm volatile ("" : : "r" (thread_id_ptr));
|
asm volatile ("" : : "r" (thread_id_ptr));
|
||||||
@ -75,14 +82,8 @@ int main(int argc, char *argv[]) {
|
|||||||
pthread_attr_init(&thread_attributes);
|
pthread_attr_init(&thread_attributes);
|
||||||
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
|
pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
|
||||||
for (int i = 1; i < num_threads; i++) {
|
for (int i = 1; i < num_threads; i++) {
|
||||||
pthread_create(&threads[i], &thread_attributes, &thread_function, NULL);
|
pthread_create(&threads[i], &thread_attributes, &thread_function, &pipefd);
|
||||||
}
|
}
|
||||||
// Signal parent that this process has started all threads.
|
thread_function(&pipefd);
|
||||||
uint8_t byte = 1;
|
|
||||||
if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) {
|
|
||||||
perror("ERROR: parent notification failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
thread_function(NULL);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -212,20 +212,28 @@ TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
// Wait for the child process to signal that it's ready.
|
|
||||||
struct pollfd pfd;
|
|
||||||
memset(&pfd, 0, sizeof(pfd));
|
|
||||||
pfd.fd = fds[0];
|
|
||||||
pfd.events = POLLIN | POLLERR;
|
|
||||||
|
|
||||||
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
|
// Wait for all child threads to indicate that they have started
|
||||||
ASSERT_EQ(1, r);
|
for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
|
||||||
ASSERT_TRUE(pfd.revents & POLLIN);
|
struct pollfd pfd;
|
||||||
uint8_t junk;
|
memset(&pfd, 0, sizeof(pfd));
|
||||||
read(fds[0], &junk, sizeof(junk));
|
pfd.fd = fds[0];
|
||||||
|
pfd.events = POLLIN | POLLERR;
|
||||||
|
|
||||||
|
const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
|
||||||
|
ASSERT_EQ(1, r);
|
||||||
|
ASSERT_TRUE(pfd.revents & POLLIN);
|
||||||
|
uint8_t junk;
|
||||||
|
ASSERT_EQ(read(fds[0], &junk, sizeof(junk)), sizeof(junk));
|
||||||
|
}
|
||||||
close(fds[0]);
|
close(fds[0]);
|
||||||
|
|
||||||
// Child is ready now.
|
// There is a race here because we may stop a child thread before
|
||||||
|
// it is actually running the busy loop. Empirically this sleep
|
||||||
|
// is sufficient to avoid the race.
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
// Children are ready now.
|
||||||
LinuxPtraceDumper dumper(child_pid);
|
LinuxPtraceDumper dumper(child_pid);
|
||||||
ASSERT_TRUE(dumper.Init());
|
ASSERT_TRUE(dumper.Init());
|
||||||
EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size());
|
EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size());
|
||||||
|
Loading…
Reference in New Issue
Block a user