Skip to content

Instantly share code, notes, and snippets.

@a3f
Created March 18, 2017 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a3f/0fe444521feca3096fc91e0bfddc1a2c to your computer and use it in GitHub Desktop.
Save a3f/0fe444521feca3096fc91e0bfddc1a2c to your computer and use it in GitHub Desktop.
Possible pthreads race bug on macOS Sierra
/*
for i in `seq 100000`; do ./a.out $i ; done && echo ' All is well!'
*/
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
void *interp(void *param) {
(void)param;
char ch;
while (read(0, &ch, sizeof ch) > 0)
;
puts("Should never be reached");
return NULL;
}
int main(int argc, char *argv[]) {
int ret;
pthread_t pthread;
ret = pthread_create(&pthread, NULL, interp, NULL);
assert(ret == 0);
ret = pthread_cancel(pthread);
assert(ret == 0);
ret = pthread_join(pthread, NULL);
assert(ret == 0);
printf("\r%s", argv[argc-1]);
return 0;
}
@a3f
Copy link
Author

a3f commented Mar 18, 2017

Compile the code and run for i in `seq 100000`; do ./a.out $i ; done && echo ' All is well!'.

After a short while (Usually before reaching 1000), the command will hang.

LLDB inspection shows that the thread is blocking on read as expected. If the user call pthread_cancel(pthread) manually on main's frame, the thread is cancelled.

So it seems, there's a race between pthread_create and pthread_cancel, which leads to the cancellation request to be lost. Inspection of the libc source didn't show any problems however. Maybe the issue is with the pthread trampoline? Regardless, this violates POSIX, as a pthread_t handle ought to be usable as soon as pthread_create returns.

The expected behavior, seen on other Unices, e.g. Linux is the command terminating at 100000 All is well!.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment