Skip to content

Commit cf3ced8

Browse files
committed
[lldb] Call Import_AppendInittab exactly once before Py_Initialize
The Python documentation [1] says that `PyImport_AppendInittab` should be called before `Py_Initialize()`. Starting with Python 3.12, this is enforced with a fatal error: Fatal Python error: PyImport_AppendInittab: PyImport_AppendInittab() may not be called after Py_Initialize() This commit ensures we only modify the table of built-in modules if Python hasn't been initialized. For Python embedded in LLDB, that means this happen exactly once, before the first call to `Py_Initialize`, which becomes a NO-OP after. However, when lldb is imported in an existing Python interpreter, Python will have already been initialized, but by definition, the lldb module will already have been loaded, so it's safe to skip adding it (again). This fixes #70453. [1] https://docs.python.org/3.12/c-api/import.html#c.PyImport_AppendInittab
1 parent 36e73e4 commit cf3ced8

File tree

1 file changed

+28
-25
lines changed

1 file changed

+28
-25
lines changed

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,24 +97,28 @@ struct InitializePythonRAII {
9797
InitializePythonRAII() {
9898
InitializePythonHome();
9999

100+
// The table of built-in modules can only be extended before Python is
101+
// initialized.
102+
if (!Py_IsInitialized()) {
100103
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
101-
// Python's readline is incompatible with libedit being linked into lldb.
102-
// Provide a patched version local to the embedded interpreter.
103-
bool ReadlinePatched = false;
104-
for (auto *p = PyImport_Inittab; p->name != nullptr; p++) {
105-
if (strcmp(p->name, "readline") == 0) {
106-
p->initfunc = initlldb_readline;
107-
break;
104+
// Python's readline is incompatible with libedit being linked into lldb.
105+
// Provide a patched version local to the embedded interpreter.
106+
bool ReadlinePatched = false;
107+
for (auto *p = PyImport_Inittab; p->name != nullptr; p++) {
108+
if (strcmp(p->name, "readline") == 0) {
109+
p->initfunc = initlldb_readline;
110+
break;
111+
}
112+
}
113+
if (!ReadlinePatched) {
114+
PyImport_AppendInittab("readline", initlldb_readline);
115+
ReadlinePatched = true;
108116
}
109-
}
110-
if (!ReadlinePatched) {
111-
PyImport_AppendInittab("readline", initlldb_readline);
112-
ReadlinePatched = true;
113-
}
114117
#endif
115118

116-
// Register _lldb as a built-in module.
117-
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
119+
// Register _lldb as a built-in module.
120+
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
121+
}
118122

119123
// Python < 3.2 and Python >= 3.2 reversed the ordering requirements for
120124
// calling `Py_Initialize` and `PyEval_InitThreads`. < 3.2 requires that you
@@ -2802,7 +2806,7 @@ bool ScriptInterpreterPythonImpl::RunScriptBasedParsedCommand(
28022806
args_arr_sp->AddStringItem(entry.ref());
28032807
}
28042808
StructuredDataImpl args_impl(args_arr_sp);
2805-
2809+
28062810
ret_val = SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
28072811
static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger_sp,
28082812
args_impl, cmd_retobj, exe_ctx_ref_sp);
@@ -2936,7 +2940,7 @@ uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject(
29362940
return result;
29372941
}
29382942

2939-
StructuredData::ObjectSP
2943+
StructuredData::ObjectSP
29402944
ScriptInterpreterPythonImpl::GetOptionsForCommandObject(
29412945
StructuredData::GenericSP cmd_obj_sp) {
29422946
StructuredData::ObjectSP result = {};
@@ -2984,7 +2988,7 @@ ScriptInterpreterPythonImpl::GetOptionsForCommandObject(
29842988
return py_return.CreateStructuredObject();
29852989
}
29862990

2987-
StructuredData::ObjectSP
2991+
StructuredData::ObjectSP
29882992
ScriptInterpreterPythonImpl::GetArgumentsForCommandObject(
29892993
StructuredData::GenericSP cmd_obj_sp) {
29902994
StructuredData::ObjectSP result = {};
@@ -3032,8 +3036,7 @@ ScriptInterpreterPythonImpl::GetArgumentsForCommandObject(
30323036
return py_return.CreateStructuredObject();
30333037
}
30343038

3035-
void
3036-
ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject(
3039+
void ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject(
30373040
StructuredData::GenericSP cmd_obj_sp) {
30383041

30393042
Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock);
@@ -3067,7 +3070,7 @@ ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject(
30673070
if (PyErr_Occurred())
30683071
PyErr_Clear();
30693072

3070-
// option_parsing_starting doesn't return anything, ignore anything but
3073+
// option_parsing_starting doesn't return anything, ignore anything but
30713074
// python errors.
30723075
unwrapOrSetPythonException(
30733076
As<bool>(implementor.CallMethod(callee_name)));
@@ -3116,15 +3119,15 @@ ScriptInterpreterPythonImpl::SetOptionValueForCommandObject(
31163119

31173120
if (PyErr_Occurred())
31183121
PyErr_Clear();
3119-
3122+
31203123
lldb::ExecutionContextRefSP exe_ctx_ref_sp;
31213124
if (exe_ctx)
31223125
exe_ctx_ref_sp.reset(new ExecutionContextRef(exe_ctx));
31233126
PythonObject ctx_ref_obj = SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp);
3124-
3125-
bool py_return = unwrapOrSetPythonException(
3126-
As<bool>(implementor.CallMethod(callee_name, ctx_ref_obj, long_option.str().c_str(),
3127-
value.str().c_str())));
3127+
3128+
bool py_return = unwrapOrSetPythonException(As<bool>(
3129+
implementor.CallMethod(callee_name, ctx_ref_obj,
3130+
long_option.str().c_str(), value.str().c_str())));
31283131

31293132
// if it fails, print the error but otherwise go on
31303133
if (PyErr_Occurred()) {

0 commit comments

Comments
 (0)