Bug 14333 - Fix the race between atexit() and exit()
Summary: Fix the race between atexit() and exit()
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: 2.27
Assignee: Paul Pluzhnikov
Depends on:
Reported: 2012-07-06 01:52 UTC by Peng Haitao
Modified: 2017-09-20 16:56 UTC (History)
6 users (show)

See Also:
Last reconfirmed:
fweimer: security-

The Patch can fix the race betweent atexit() and exit() (2.14 KB, text/plain)
2012-07-06 01:52 UTC, Peng Haitao
The Patch can fix the race betweent atexit() and exit() (2.72 KB, patch)
2012-10-12 02:41 UTC, Peng Haitao
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Peng Haitao 2012-07-06 01:52:47 UTC
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 =
g. programme may be Segmentation fault
Comment 1 Carlos O'Donell 2012-10-11 14:16:56 UTC
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.
Comment 2 Peng Haitao 2012-10-12 02:41:37 UTC
Created attachment 6682 [details]
The Patch can fix the race betweent atexit() and exit()
Comment 3 Siddhesh Poyarekar 2012-10-18 03:09:57 UTC
Please post the patch on libc-alpha.  If you've posted before and not got a response, then please repost it.
Comment 4 Peng Haitao 2012-10-22 07:52:53 UTC
(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

Comment 5 Paul Pluzhnikov 2016-08-12 23:20:07 UTC
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) {
  return NULL;

int main(int argc, char **argv) {
  size_t i;
  pthread_t thr;
  pthread_attr_t attr;
  pthread_attr_setdetachstate(&attr, 1);

  for (i = 0; i < kNumThreads; ++i) {
    pthread_create(&thr, &attr, threadfunc, NULL);


Crashes reliably with today's trunk. AddressSanitizer shows:

./elf/ld.so --library-path .:nptl:math:dlfcn ./a.out
==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

$ ./elf/ld.so --library-path .:nptl:math:dlfcn ./a.out
==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
Comment 7 Carlos O'Donell 2016-08-15 19:18:18 UTC
(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.
Comment 8 Paul Pluzhnikov 2017-04-22 23:35:08 UTC
Re-confirmed with current (5ea9ce3749007348a8d12e8eef9e0ccc6fd90aec) trunk with test case from #c5.

Looks like we've hit this bug again. Google ref: b/36123737.
Comment 9 cvs-commit@gcc.gnu.org 2017-09-20 16:32:28 UTC
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 -----------------------------------------------------------------

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