]> git.ipfire.org Git - thirdparty/glibc.git/blame - stdlib/cxa_finalize.c
Fix http: URL in 'configure'
[thirdparty/glibc.git] / stdlib / cxa_finalize.c
CommitLineData
04277e02 1/* Copyright (C) 1999-2019 Free Software Foundation, Inc.
c41041bc
UD
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
c41041bc
UD
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
c41041bc 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
c41041bc
UD
17
18#include <assert.h>
19#include <stdlib.h>
c41041bc 20#include "exit.h"
d1f69fed 21#include <fork.h>
a3c88553 22#include <sysdep.h>
e054f494 23#include <stdint.h>
c41041bc
UD
24
25/* If D is non-NULL, call all functions registered with `__cxa_atexit'
4e648ea3
UD
26 with the same dso handle. Otherwise, if D is NULL, call all of the
27 registered handlers. */
c41041bc
UD
28void
29__cxa_finalize (void *d)
30{
31 struct exit_function_list *funcs;
32
26e70aec
PP
33 __libc_lock_lock (__exit_funcs_lock);
34
a92b1166 35 restart:
c41041bc
UD
36 for (funcs = __exit_funcs; funcs; funcs = funcs->next)
37 {
38 struct exit_function *f;
39
40 for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
26e70aec
PP
41 if ((d == NULL || d == f->func.cxa.dso_handle) && f->flavor == ef_cxa)
42 {
43 const uint64_t check = __new_exitfn_called;
44 void (*cxafn) (void *arg, int status) = f->func.cxa.fn;
45 void *cxaarg = f->func.cxa.arg;
46
47 /* We don't want to run this cleanup more than once. The Itanium
48 C++ ABI requires that multiple calls to __cxa_finalize not
49 result in calling termination functions more than once. One
50 potential scenario where that could happen is with a concurrent
51 dlclose and exit, where the running dlclose must at some point
52 release the list lock, an exiting thread may acquire it, and
53 without setting flavor to ef_free, might re-run this destructor
54 which could result in undefined behaviour. Therefore we must
55 set flavor to ef_free to avoid calling this destructor again.
56 Note that the concurrent exit must also take the dynamic loader
57 lock (for library finalizer processing) and therefore will
58 block while dlclose completes the processing of any in-progress
59 exit functions. Lastly, once we release the list lock for the
60 entry marked ef_free, we must not read from that entry again
61 since it may have been reused by the time we take the list lock
62 again. Lastly the detection of new registered exit functions is
63 based on a monotonically incrementing counter, and there is an
64 ABA if between the unlock to run the exit function and the
65 re-lock after completion the user registers 2^64 exit functions,
66 the implementation will not detect this and continue without
67 executing any more functions.
bd3754dc 68
26e70aec
PP
69 One minor issue remains: A registered exit function that is in
70 progress by a call to dlclose() may not completely finish before
71 the next registered exit function is run. This may, according to
72 some readings of POSIX violate the requirement that functions
73 run in effective LIFO order. This should probably be fixed in a
74 future implementation to ensure the functions do not run in
75 parallel. */
76 f->flavor = ef_free;
a92b1166 77
a3c88553 78#ifdef PTR_DEMANGLE
26e70aec 79 PTR_DEMANGLE (cxafn);
a3c88553 80#endif
26e70aec
PP
81 /* Unlock the list while we call a foreign function. */
82 __libc_lock_unlock (__exit_funcs_lock);
83 cxafn (cxaarg, 0);
84 __libc_lock_lock (__exit_funcs_lock);
a92b1166 85
26e70aec
PP
86 /* It is possible that that last exit function registered
87 more exit functions. Start the loop over. */
88 if (__glibc_unlikely (check != __new_exitfn_called))
89 goto restart;
90 }
c41041bc 91 }
d1f69fed 92
610e67ed
UD
93 /* Also remove the quick_exit handlers, but do not call them. */
94 for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next)
95 {
96 struct exit_function *f;
97
98 for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
99 if (d == NULL || d == f->func.cxa.dso_handle)
100 f->flavor = ef_free;
101 }
102
4e648ea3
UD
103 /* Remove the registered fork handlers. We do not have to
104 unregister anything if the program is going to terminate anyway. */
d1f69fed 105#ifdef UNREGISTER_ATFORK
4e648ea3
UD
106 if (d != NULL)
107 UNREGISTER_ATFORK (d);
d1f69fed 108#endif
26e70aec 109 __libc_lock_unlock (__exit_funcs_lock);
c41041bc 110}