(zero) if not. After :c:func:`Py_FinalizeEx` is called, this returns false until
:c:func:`Py_Initialize` is called again.
+ .. versionchanged:: next
+ This function no longer returns true until initialization has fully
+ completed, including import of the :mod:`site` module. Previously it
+ could return true while :c:func:`Py_Initialize` was still running.
+
.. c:function:: int Py_IsFinalizing()
}
}
+// Atomic so a thread that reads initialized=1 observes all writes
+// from the initialization sequence (gh-146302).
+
+static inline int
+_PyRuntimeState_GetCoreInitialized(_PyRuntimeState *runtime) {
+ return _Py_atomic_load_int(&runtime->core_initialized);
+}
+
+static inline void
+_PyRuntimeState_SetCoreInitialized(_PyRuntimeState *runtime, int initialized) {
+ _Py_atomic_store_int(&runtime->core_initialized, initialized);
+}
+
+static inline int
+_PyRuntimeState_GetInitialized(_PyRuntimeState *runtime) {
+ return _Py_atomic_load_int(&runtime->initialized);
+}
+
+static inline void
+_PyRuntimeState_SetInitialized(_PyRuntimeState *runtime, int initialized) {
+ _Py_atomic_store_int(&runtime->initialized, initialized);
+}
+
#ifdef __cplusplus
}
/* Is Python preinitialized? Set to 1 by Py_PreInitialize() */
int preinitialized;
- /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */
+ /* Is Python core initialized? Set to 1 by _Py_InitializeCore().
+
+ Use _PyRuntimeState_GetCoreInitialized() and
+ _PyRuntimeState_SetCoreInitialized() to access it,
+ don't access it directly. */
int core_initialized;
- /* Is Python fully initialized? Set to 1 by Py_Initialize() */
+ /* Is Python fully initialized? Set to 1 by Py_Initialize().
+
+ Use _PyRuntimeState_GetInitialized() and
+ _PyRuntimeState_SetInitialized() to access it,
+ don't access it directly. */
int initialized;
/* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize()
out, err = self.run_embedded_interpreter("test_init_in_background_thread")
self.assertEqual(err, "")
+ def test_isinitialized_false_during_site_import(self):
+ # gh-146302: Py_IsInitialized() must not return true during site import.
+ out, err = self.run_embedded_interpreter(
+ "test_isinitialized_false_during_site_import")
+ self.assertEqual(err, "")
+
class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
def test_open_code_hook(self):
--- /dev/null
+:c:func:`Py_IsInitialized` no longer returns true until initialization has
+fully completed, including import of the :mod:`site` module. The underlying
+runtime flags now use atomic operations.
config._init_main = 0;
init_from_config_clear(&config);
+ assert(Py_IsInitialized() == 0);
+
/* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */
int res = PyRun_SimpleString(
"import sys; "
return PyThread_join_thread(handle);
}
+/* gh-146302: Py_IsInitialized() must not return true during site import. */
+static int _initialized_during_site_import = -1; /* -1 = not observed */
+
+static int hook_check_initialized_on_site_import(
+ const char *event, PyObject *args, void *userData)
+{
+ if (strcmp(event, "import") == 0 && args != NULL) {
+ PyObject *name = PyTuple_GetItem(args, 0);
+ if (name != NULL && PyUnicode_Check(name)
+ && PyUnicode_CompareWithASCIIString(name, "site") == 0
+ && _initialized_during_site_import == -1)
+ {
+ _initialized_during_site_import = Py_IsInitialized();
+ }
+ }
+ return 0;
+}
+
+static int test_isinitialized_false_during_site_import(void)
+{
+ _initialized_during_site_import = -1;
+
+ /* Register audit hook before initialization */
+ PySys_AddAuditHook(hook_check_initialized_on_site_import, NULL);
+
+ _testembed_initialize();
+
+ if (_initialized_during_site_import == -1) {
+ error("audit hook never observed site import");
+ Py_Finalize();
+ return 1;
+ }
+ if (_initialized_during_site_import != 0) {
+ error("Py_IsInitialized() was true during site import");
+ Py_Finalize();
+ return 1;
+ }
+ if (!Py_IsInitialized()) {
+ error("Py_IsInitialized() was false after Py_Initialize()");
+ return 1;
+ }
+
+ Py_Finalize();
+ return 0;
+}
+
#ifndef MS_WINDOWS
#include "test_frozenmain.h" // M_test_frozenmain
{"test_init_use_frozen_modules", test_init_use_frozen_modules},
{"test_init_main_interpreter_settings", test_init_main_interpreter_settings},
{"test_init_in_background_thread", test_init_in_background_thread},
+ {"test_isinitialized_false_during_site_import", test_isinitialized_false_during_site_import},
// Audit
{"test_open_code_hook", test_open_code_hook},
return status;
}
- if (_PyRuntime.core_initialized) {
+ if (_Py_IsCoreInitialized()) {
/* bpo-34008: Calling this functions after Py_Initialize() ignores
the new configuration. */
return _PyStatus_OK();
int
_Py_IsCoreInitialized(void)
{
- return _PyRuntime.core_initialized;
+ return _PyRuntimeState_GetCoreInitialized(&_PyRuntime);
}
int
Py_IsInitialized(void)
{
- return _PyRuntime.initialized;
+ return _PyRuntimeState_GetInitialized(&_PyRuntime);
}
pycore_init_runtime(_PyRuntimeState *runtime,
const PyConfig *config)
{
- if (runtime->initialized) {
+ if (_PyRuntimeState_GetInitialized(runtime)) {
return _PyStatus_ERR("main interpreter already initialized");
}
}
/* Only when we get here is the runtime core fully initialized */
- runtime->core_initialized = 1;
+ _PyRuntimeState_SetCoreInitialized(runtime, 1);
return _PyStatus_OK();
}
* or pure Python code in the standard library won't work.
*/
if (is_main_interp) {
- interp->runtime->initialized = 1;
+ _PyRuntimeState_SetInitialized(interp->runtime, 1);
}
return _PyStatus_OK();
}
Py_XDECREF(warnings_module);
}
Py_XDECREF(warnoptions);
-
- interp->runtime->initialized = 1;
}
if (config->site_import) {
assert(!_PyErr_Occurred(tstate));
+ if (is_main_interp) {
+ _PyRuntimeState_SetInitialized(interp->runtime, 1);
+ }
+
return _PyStatus_OK();
}
pyinit_main(PyThreadState *tstate)
{
PyInterpreterState *interp = tstate->interp;
- if (!interp->runtime->core_initialized) {
+ if (!_PyRuntimeState_GetCoreInitialized(interp->runtime)) {
return _PyStatus_ERR("runtime core not initialized");
}
- if (interp->runtime->initialized) {
+ if (_PyRuntimeState_GetInitialized(interp->runtime)) {
return pyinit_main_reconfigure(tstate);
}
if (_PyStatus_EXCEPTION(status)) {
Py_ExitStatusException(status);
}
- _PyRuntimeState *runtime = &_PyRuntime;
- if (runtime->initialized) {
+ if (Py_IsInitialized()) {
/* bpo-33932: Calling Py_Initialize() twice does nothing. */
return;
}
int status = 0;
/* Bail out early if already finalized (or never initialized). */
- if (!runtime->initialized) {
+ if (!_PyRuntimeState_GetInitialized(runtime)) {
return status;
}
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
_PyInterpreterState_SetFinalizing(tstate->interp, tstate);
_PyRuntimeState_SetFinalizing(runtime, tstate);
- runtime->initialized = 0;
- runtime->core_initialized = 0;
+ _PyRuntimeState_SetInitialized(runtime, 0);
+ _PyRuntimeState_SetCoreInitialized(runtime, 0);
// XXX Call something like _PyImport_Disable() here?
}
_PyRuntimeState *runtime = &_PyRuntime;
- if (!runtime->initialized) {
+ if (!_PyRuntimeState_GetInitialized(runtime)) {
return _PyStatus_ERR("Py_Initialize must be called first");
}
_Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2);
PUTS(fd, ")");
}
- else if (runtime->initialized) {
+ else if (_PyRuntimeState_GetInitialized(runtime)) {
PUTS(fd, "initialized");
}
- else if (runtime->core_initialized) {
+ else if (_PyRuntimeState_GetCoreInitialized(runtime)) {
PUTS(fd, "core initialized");
}
else if (runtime->preinitialized) {
{
assert(!runtime->preinitializing);
assert(!runtime->preinitialized);
- assert(!runtime->core_initialized);
- assert(!runtime->initialized);
+ assert(!_PyRuntimeState_GetCoreInitialized(runtime));
+ assert(!_PyRuntimeState_GetInitialized(runtime));
assert(!runtime->_initialized);
runtime->open_code_hook = open_code_hook;
#include "pycore_pymem.h" // _PyMem_DefaultRawFree()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_pystats.h" // _Py_PrintSpecializationStats()
+#include "pycore_runtime.h" // _PyRuntimeState_Get*()
#include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags()
#include "pycore_sysmodule.h" // export _PySys_GetSizeOf()
#include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal()
PySys_AddAuditHook() can be called before Python is initialized. */
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate;
- if (runtime->initialized) {
+ if (_PyRuntimeState_GetInitialized(runtime)) {
tstate = _PyThreadState_GET();
}
else {