diff options
author | Paul Pluzhnikov <ppluzhnikov@google.com> | 2017-09-21 12:14:41 -0700 |
---|---|---|
committer | Paul Pluzhnikov <ppluzhnikov@google.com> | 2017-09-21 12:14:41 -0700 |
commit | e5e4d7cc056ffae51fc55b66d9dd0abd99927486 (patch) | |
tree | 2290540b926efebc5936d984a773688247a5f736 /stdlib/exit.c | |
parent | c10c5267a8c95ffea1fad70e2bf047c1dd3dfd48 (diff) | |
download | glibc-e5e4d7cc056ffae51fc55b66d9dd0abd99927486.zip glibc-e5e4d7cc056ffae51fc55b66d9dd0abd99927486.tar.gz glibc-e5e4d7cc056ffae51fc55b66d9dd0abd99927486.tar.bz2 |
Fix BZ# 22180.
POSIX requires that dlclose() and exit() be thread safe, therefore
you can have one thread in the middle of dlclose() and another thread
executing exit() without causing any undefined behaviour on the part
of the implementation.
The existing implementation had a flaw that exit() exit handler processing
did not consider a concurrent dlclose() and would not mark already run
exit handlers using the ef_free flavour. The consequence of this is that
a concurrent exit() with dlclose() will run all the exit handlers that
dlclose() had not yet run, but then will block on the loader lock. The
concurrent dlclose() will continue to run all the exit handlers again
(twice) in violation of the Itanium C++ ABI requirements for __cxa_atexit().
This commit fixes this by having exit() mark all handlers with ef_free to
ensure that concurrent dlclose() won't re-run registered exit handlers that
have already run.
Diffstat (limited to 'stdlib/exit.c')
-rw-r--r-- | stdlib/exit.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/stdlib/exit.c b/stdlib/exit.c index b74f182..fec91aa 100644 --- a/stdlib/exit.c +++ b/stdlib/exit.c @@ -69,8 +69,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, while (cur->idx > 0) { - const struct exit_function *const f = - &cur->fns[--cur->idx]; + struct exit_function *const f = &cur->fns[--cur->idx]; const uint64_t new_exitfn_called = __new_exitfn_called; /* Unlock the list while we call a foreign function. */ @@ -99,6 +98,9 @@ __run_exit_handlers (int status, struct exit_function_list **listp, atfct (); break; case ef_cxa: + /* To avoid dlclose/exit race calling cxafct twice (BZ 22180), + we must mark this function as ef_free. */ + f->flavor = ef_free; cxafct = f->func.cxa.fn; #ifdef PTR_DEMANGLE PTR_DEMANGLE (cxafct); |