Created attachment 6511 [details] The Patch can fix the race betweent atexit() and exit() exit() uses global variable __exit_funcs indirectly, which are not protected. It is not safe in multithread circumstance. When call exit() and atexit() simultaneously in multithread circumstance, the following case will cause unsafe. The case has main process A and thread B. a. thread B call atexit() b. process A call exit() to traverse the __exit_funcs list c. thread B call calloc() to create a new entry p, and next to listp: p->next = *listp; d. process A modify listp to cur's next, then free cur: *listp = cur->next; e. thread B modify listp to p: *listp = p; f. when get f, the f is undefined: const struct exit_function *const f = &cur->fns[--cur->idx]; g. programme may be Segmentation fault
We're seeing failures on hppa in this area while running some of gcc's testsuite and it looks like a similar issue. John David Anglin is investigating for me on the gcc side.
Created attachment 6682 [details] The Patch can fix the race betweent atexit() and exit()
Please post the patch on libc-alpha. If you've posted before and not got a response, then please repost it.
(In reply to comment #3) > Please post the patch on libc-alpha. If you've posted before and not got a > response, then please repost it. I have reposted the patch to libc-alpha, please review. URL: http://sourceware.org/ml/libc-alpha/2012-10/msg00567.html Thanks.
Test case that reliably reproduce the crash, courtesy Ricky Zhou <rickyz@google.com>: #include <stdio.h> #include <stdlib.h> #include <pthread.h> const size_t kNumThreads = 1024; const size_t kNumHandlers = 1024; void no_op() {} void *threadfunc(void *unused) { size_t i; for (i = 0; i < kNumHandlers; ++i) { atexit(&no_op); } return NULL; } int main(int argc, char **argv) { size_t i; pthread_t thr; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, 1); for (i = 0; i < kNumThreads; ++i) { pthread_create(&thr, &attr, threadfunc, NULL); } exit(0); } Crashes reliably with today's trunk. AddressSanitizer shows: ./elf/ld.so --library-path .:nptl:math:dlfcn ./a.out ASAN:DEADLYSIGNAL ================================================================= ==28165==ERROR: AddressSanitizer: SEGV on unknown address 0x61905e800009 (pc 0x7fa05bbc1d50 bp 0x619004fb4680 sp 0x7fa053bf5e40 T1014) #0 0x7fa05bbc1d4f in __new_exitfn /glibc-git/stdlib/cxa_atexit.c:74 #1 0x7fa05bbc1ee8 in __internal_atexit /glibc-git/stdlib/cxa_atexit.c:35 #2 0x7fa05bbc1ee8 in __GI___cxa_atexit /glibc-git/stdlib/cxa_atexit.c:58 #3 0x7fa05c171746 in __interceptor___cxa_atexit ../../../../libsanitizer/asan/asan_interceptors.cc:716 #4 0x400acc (/glibc-git/build-system-gcc/elf/ld.so+0x400acc) #5 0x7fa05bf2c7b3 in start_thread /nptl/pthread_create.c:333 #6 0x7fa05bc703ae in __clone (libc.so.6+0xe53ae) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /glibc-git/stdlib/cxa_atexit.c:74 in __new_exitfn Thread T1014 created by T0 here: #0 0x7fa05c171aa9 in __interceptor_pthread_create ../../../../libsanitizer/asan/asan_interceptors.cc:236 #1 0x400bc5 (/glibc-git/build-system-gcc/elf/ld.so+0x400bc5) #2 0x7fa05bbacd34 in __libc_start_main ../csu/libc-start.c:289 ==28165==ABORTING $ ./elf/ld.so --library-path .:nptl:math:dlfcn ./a.out ================================================================= ASAN:DEADLYSIGNAL ==29431==AddressSanitizer: while reporting a bug found another one. Ignoring. ==29431==ERROR: AddressSanitizer: attempting double-free on 0x619004e67480 in thread T0: #0 0x7f5038e35a80 in __interceptor_free ../../../../libsanitizer/asan/asan_malloc_linux.cc:45 #1 0x7f50387f5c5f in __run_exit_handlers /glibc-git/stdlib/exit.c:92 #2 0x7f50387f5c99 in __GI_exit /glibc-git/stdlib/exit.c:105 #3 0x400bea (/glibc-git/build-system-gcc/elf/ld.so+0x400bea) #4 0x7f50387e0d34 in __libc_start_main ../csu/libc-start.c:289 #5 0x4009c8 (/glibc-git/build-system-gcc/elf/ld.so+0x4009c8) 0x619004e67480 is located 0 bytes inside of 1040-byte region [0x619004e67480,0x619004e67890) freed by thread T0 here: #0 0x7f5038e35a80 in __interceptor_free ../../../../libsanitizer/asan/asan_malloc_linux.cc:45 #1 0x7f50387f5c5f in __run_exit_handlers /glibc-git/stdlib/exit.c:92 previously allocated by thread T983 here: #0 0x7f5038e35f40 in __interceptor_calloc ../../../../libsanitizer/asan/asan_malloc_linux.cc:70 #1 0x7f50387f5e42 in __new_exitfn /glibc-git/stdlib/cxa_atexit.c:101 Thread T983 created by T0 here: #0 0x7f5038da5aa9 in __interceptor_pthread_create ../../../../libsanitizer/asan/asan_interceptors.cc:236 #1 0x400bc5 (/glibc-git/build-system-gcc/elf/ld.so+0x400bc5) #2 0x7f50387e0d34 in __libc_start_main ../csu/libc-start.c:289 SUMMARY: AddressSanitizer: double-free ../../../../libsanitizer/asan/asan_malloc_linux.cc:45 in __interceptor_free
Previous attempts to fix this: https://sourceware.org/ml/libc-help/2008-06/msg00011.html https://sourceware.org/ml/libc-alpha/2008-09/msg00013.html https://sourceware.org/ml/libc-alpha/2012-10/msg00567.html
(In reply to Paul Pluzhnikov from comment #6) > Previous attempts to fix this: > > https://sourceware.org/ml/libc-help/2008-06/msg00011.html > https://sourceware.org/ml/libc-alpha/2008-09/msg00013.html These two changes are potentially acceptable since IBM has copyright assignments in place. Someone needs to review in more detail. > https://sourceware.org/ml/libc-alpha/2012-10/msg00567.html These changes from Fujitsu should not be reviewed. Fujitsu does not have copyright assignment and looking at the patches could taint a reviewer.
Re-confirmed with current (5ea9ce3749007348a8d12e8eef9e0ccc6fd90aec) trunk with test case from #c5. Looks like we've hit this bug again. Google ref: b/36123737.
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU C Library master sources". The branch, master has been updated via 26e70aec7028feeb196744eb97cd2dff3670b7aa (commit) from 0525ce4850f2c22a235dcd3422bc92f40815f377 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=26e70aec7028feeb196744eb97cd2dff3670b7aa commit 26e70aec7028feeb196744eb97cd2dff3670b7aa Author: Paul Pluzhnikov <ppluzhnikov@google.com> Date: Wed Sep 20 09:31:48 2017 -0700 Fix BZ 14333 ----------------------------------------------------------------------- Summary of changes: ChangeLog | 22 ++++++++++++ stdlib/Makefile | 9 ++++- stdlib/cxa_atexit.c | 28 +++++++++------ stdlib/cxa_finalize.c | 68 ++++++++++++++++++++++++++----------- stdlib/exit.c | 36 +++++++++++++++++++- stdlib/exit.h | 19 ++++++++++- stdlib/on_exit.c | 13 +++++-- stdlib/test-at_quick_exit-race.c | 32 ++++++++++++++++++ stdlib/test-atexit-race.c | 31 +++++++++++++++++ stdlib/test-cxa_atexit-race.c | 35 +++++++++++++++++++ stdlib/test-on_exit-race.c | 31 +++++++++++++++++ 11 files changed, 285 insertions(+), 39 deletions(-) create mode 100644 stdlib/test-at_quick_exit-race.c create mode 100644 stdlib/test-atexit-race.c create mode 100644 stdlib/test-cxa_atexit-race.c create mode 100644 stdlib/test-on_exit-race.c
Also: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a856d4d4a8a56eaefdddb58884bfa2bfe922ee4c