mirror of
https://github.com/python/cpython.git
synced 2025-09-25 01:43:11 +00:00
[3.12] gh-100227: Lock Around Use of the Global "atexit" State (gh-105514) (gh-105517)
The risk of a race with this state is relatively low, but we play it safe anyway.
(cherry picked from commit 7799c8e678
)
Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
This commit is contained in:
parent
8698fa83f6
commit
2ad2bd8b14
4 changed files with 488 additions and 457 deletions
File diff suppressed because it is too large
Load diff
|
@ -15,6 +15,7 @@ extern "C" {
|
||||||
typedef void (*atexit_callbackfunc)(void);
|
typedef void (*atexit_callbackfunc)(void);
|
||||||
|
|
||||||
struct _atexit_runtime_state {
|
struct _atexit_runtime_state {
|
||||||
|
PyThread_type_lock mutex;
|
||||||
#define NEXITFUNCS 32
|
#define NEXITFUNCS 32
|
||||||
atexit_callbackfunc callbacks[NEXITFUNCS];
|
atexit_callbackfunc callbacks[NEXITFUNCS];
|
||||||
int ncallbacks;
|
int ncallbacks;
|
||||||
|
|
|
@ -2974,24 +2974,35 @@ wait_for_thread_shutdown(PyThreadState *tstate)
|
||||||
|
|
||||||
int Py_AtExit(void (*func)(void))
|
int Py_AtExit(void (*func)(void))
|
||||||
{
|
{
|
||||||
if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS)
|
struct _atexit_runtime_state *state = &_PyRuntime.atexit;
|
||||||
|
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
||||||
|
if (state->ncallbacks >= NEXITFUNCS) {
|
||||||
|
PyThread_release_lock(state->mutex);
|
||||||
return -1;
|
return -1;
|
||||||
_PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func;
|
}
|
||||||
|
state->callbacks[state->ncallbacks++] = func;
|
||||||
|
PyThread_release_lock(state->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
call_ll_exitfuncs(_PyRuntimeState *runtime)
|
call_ll_exitfuncs(_PyRuntimeState *runtime)
|
||||||
{
|
{
|
||||||
|
atexit_callbackfunc exitfunc;
|
||||||
struct _atexit_runtime_state *state = &runtime->atexit;
|
struct _atexit_runtime_state *state = &runtime->atexit;
|
||||||
|
|
||||||
|
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
||||||
while (state->ncallbacks > 0) {
|
while (state->ncallbacks > 0) {
|
||||||
/* pop last function from the list */
|
/* pop last function from the list */
|
||||||
state->ncallbacks--;
|
state->ncallbacks--;
|
||||||
atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks];
|
exitfunc = state->callbacks[state->ncallbacks];
|
||||||
state->callbacks[state->ncallbacks] = NULL;
|
state->callbacks[state->ncallbacks] = NULL;
|
||||||
|
|
||||||
|
PyThread_release_lock(state->mutex);
|
||||||
exitfunc();
|
exitfunc();
|
||||||
|
PyThread_acquire_lock(state->mutex, WAIT_LOCK);
|
||||||
}
|
}
|
||||||
|
PyThread_release_lock(state->mutex);
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
|
|
@ -380,7 +380,16 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
|
||||||
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
|
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
|
||||||
_Py_COMP_DIAG_POP
|
_Py_COMP_DIAG_POP
|
||||||
|
|
||||||
#define NUMLOCKS 5
|
#define NUMLOCKS 6
|
||||||
|
#define LOCKS_INIT(runtime) \
|
||||||
|
{ \
|
||||||
|
&(runtime)->interpreters.mutex, \
|
||||||
|
&(runtime)->xidregistry.mutex, \
|
||||||
|
&(runtime)->getargs.mutex, \
|
||||||
|
&(runtime)->unicode_state.ids.lock, \
|
||||||
|
&(runtime)->imports.extensions.mutex, \
|
||||||
|
&(runtime)->atexit.mutex, \
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
|
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
|
||||||
|
@ -427,13 +436,7 @@ init_runtime(_PyRuntimeState *runtime,
|
||||||
|
|
||||||
PyPreConfig_InitPythonConfig(&runtime->preconfig);
|
PyPreConfig_InitPythonConfig(&runtime->preconfig);
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = {
|
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
||||||
&runtime->interpreters.mutex,
|
|
||||||
&runtime->xidregistry.mutex,
|
|
||||||
&runtime->getargs.mutex,
|
|
||||||
&runtime->unicode_state.ids.lock,
|
|
||||||
&runtime->imports.extensions.mutex,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
for (int i = 0; i < NUMLOCKS; i++) {
|
||||||
assert(locks[i] != NULL);
|
assert(locks[i] != NULL);
|
||||||
*lockptrs[i] = locks[i];
|
*lockptrs[i] = locks[i];
|
||||||
|
@ -512,13 +515,7 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
|
||||||
LOCK = NULL; \
|
LOCK = NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = {
|
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
||||||
&runtime->interpreters.mutex,
|
|
||||||
&runtime->xidregistry.mutex,
|
|
||||||
&runtime->getargs.mutex,
|
|
||||||
&runtime->unicode_state.ids.lock,
|
|
||||||
&runtime->imports.extensions.mutex,
|
|
||||||
};
|
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
for (int i = 0; i < NUMLOCKS; i++) {
|
||||||
FREE_LOCK(*lockptrs[i]);
|
FREE_LOCK(*lockptrs[i]);
|
||||||
}
|
}
|
||||||
|
@ -541,13 +538,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
|
||||||
PyMemAllocatorEx old_alloc;
|
PyMemAllocatorEx old_alloc;
|
||||||
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
|
||||||
|
|
||||||
PyThread_type_lock *lockptrs[NUMLOCKS] = {
|
PyThread_type_lock *lockptrs[NUMLOCKS] = LOCKS_INIT(runtime);
|
||||||
&runtime->interpreters.mutex,
|
|
||||||
&runtime->xidregistry.mutex,
|
|
||||||
&runtime->getargs.mutex,
|
|
||||||
&runtime->unicode_state.ids.lock,
|
|
||||||
&runtime->imports.extensions.mutex,
|
|
||||||
};
|
|
||||||
int reinit_err = 0;
|
int reinit_err = 0;
|
||||||
for (int i = 0; i < NUMLOCKS; i++) {
|
for (int i = 0; i < NUMLOCKS; i++) {
|
||||||
reinit_err += _PyThread_at_fork_reinit(lockptrs[i]);
|
reinit_err += _PyThread_at_fork_reinit(lockptrs[i]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue