From 9245a6f615248ac403d27b6e383460006680d6d9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 1 Aug 2025 15:28:21 -0700 Subject: [PATCH] [lldb] Reimplment PyRun_SimpleString using the Python stable C API Reimplment PyRun_SimpleString using the Python stable C API and the RunString helper. --- .../Python/PythonDataObjects.cpp | 16 +++++++ .../Python/PythonDataObjects.h | 1 + .../Python/ScriptInterpreterPython.cpp | 48 +++++++++---------- .../Python/ScriptInterpreterPythonImpl.h | 2 +- .../Python/PythonTestSuite.cpp | 2 +- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 9fe282415459a..42dc579206b44 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -1492,6 +1492,22 @@ PyObject *RunString(const char *str, int start, PyObject *globals, return result; } + +int RunSimpleString(const char *str) { + PyObject *main_module = PyImport_AddModule("__main__"); + if (!main_module) + return -1; + + PyObject *globals = PyModule_GetDict(main_module); + if (!globals) + return -1; + + PyObject *result = RunString(str, Py_file_input, globals, globals); + if (!result) + return -1; + + return 0; +} } // namespace python } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 6a5dd43096363..0c484b18c23b7 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -782,6 +782,7 @@ class StructuredPythonObject : public StructuredData::Generic { PyObject *RunString(const char *str, int start, PyObject *globals, PyObject *locals); +int RunSimpleString(const char *str); } // namespace python } // namespace lldb_private diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index ce775690b02bf..300518f2edba1 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -420,13 +420,13 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) run_string.Printf("%s = dict()", m_dictionary_name.c_str()); Locker locker(this, Locker::AcquireLock, Locker::FreeAcquiredLock); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); run_string.Clear(); run_string.Printf( "run_one_line (%s, 'import copy, keyword, os, re, sys, uuid, lldb')", m_dictionary_name.c_str()); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); // Reloading modules requires a different syntax in Python 2 and Python 3. // This provides a consistent syntax no matter what version of Python. @@ -434,7 +434,7 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) run_string.Printf( "run_one_line (%s, 'from importlib import reload as reload_module')", m_dictionary_name.c_str()); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); // WARNING: temporary code that loads Cocoa formatters - this should be done // on a per-platform basis rather than loading the whole set and letting the @@ -444,20 +444,20 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) run_string.Printf( "run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp')", m_dictionary_name.c_str()); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); run_string.Clear(); run_string.Printf("run_one_line (%s, 'import lldb.embedded_interpreter; from " "lldb.embedded_interpreter import run_python_interpreter; " "from lldb.embedded_interpreter import run_one_line')", m_dictionary_name.c_str()); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); run_string.Clear(); run_string.Printf("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 "')", m_dictionary_name.c_str(), m_debugger.GetID()); - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); } ScriptInterpreterPythonImpl::~ScriptInterpreterPythonImpl() { @@ -572,8 +572,8 @@ void ScriptInterpreterPythonImpl::LeaveSession() { log->PutCString("ScriptInterpreterPythonImpl::LeaveSession()"); // Unset the LLDB global variables. - PyRun_SimpleString("lldb.debugger = None; lldb.target = None; lldb.process " - "= None; lldb.thread = None; lldb.frame = None"); + RunSimpleString("lldb.debugger = None; lldb.target = None; lldb.process " + "= None; lldb.thread = None; lldb.frame = None"); // checking that we have a valid thread state - since we use our own // threading and locking in some (rare) cases during cleanup Python may end @@ -674,7 +674,7 @@ bool ScriptInterpreterPythonImpl::EnterSession(uint16_t on_entry_flags, run_string.PutCString("')"); } - PyRun_SimpleString(run_string.GetData()); + RunSimpleString(run_string.GetData()); run_string.Clear(); PythonDictionary &sys_module_dict = GetSysModuleDictionary(); @@ -816,9 +816,9 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( if (!command.empty()) { // We want to call run_one_line, passing in the dictionary and the command - // string. We cannot do this through PyRun_SimpleString here because the + // string. We cannot do this through RunSimpleString here because the // command string may contain escaped characters, and putting it inside - // another string to pass to PyRun_SimpleString messes up the escaping. So + // another string to pass to RunSimpleString messes up the escaping. So // we use the following more complicated method to pass the command string // directly down to Python. llvm::Expected> @@ -3057,7 +3057,7 @@ void ScriptInterpreterPythonImpl::Initialize() { // Update the path python uses to search for modules to include the current // directory. - PyRun_SimpleString("import sys"); + RunSimpleString("import sys"); AddToSysPath(AddLocation::End, "."); // Don't denormalize paths when calling file_spec.GetPath(). On platforms @@ -3069,10 +3069,10 @@ void ScriptInterpreterPythonImpl::Initialize() { if (FileSpec file_spec = HostInfo::GetShlibDir()) AddToSysPath(AddLocation::Beginning, file_spec.GetPath(false)); - PyRun_SimpleString("sys.dont_write_bytecode = 1; import " - "lldb.embedded_interpreter; from " - "lldb.embedded_interpreter import run_python_interpreter; " - "from lldb.embedded_interpreter import run_one_line"); + RunSimpleString("sys.dont_write_bytecode = 1; import " + "lldb.embedded_interpreter; from " + "lldb.embedded_interpreter import run_python_interpreter; " + "from lldb.embedded_interpreter import run_one_line"); #if LLDB_USE_PYTHON_SET_INTERRUPT // Python will not just overwrite its internal SIGINT handler but also the @@ -3084,13 +3084,13 @@ void ScriptInterpreterPythonImpl::Initialize() { // normal Python REPL signal handler which raises a KeyboardInterrupt. // Also make sure to not pollute the user's REPL with the signal module nor // our utility function. - PyRun_SimpleString("def lldb_setup_sigint_handler():\n" - " import signal;\n" - " def signal_handler(sig, frame):\n" - " raise KeyboardInterrupt()\n" - " signal.signal(signal.SIGINT, signal_handler);\n" - "lldb_setup_sigint_handler();\n" - "del lldb_setup_sigint_handler\n"); + RunSimpleString("def lldb_setup_sigint_handler():\n" + " import signal;\n" + " def signal_handler(sig, frame):\n" + " raise KeyboardInterrupt()\n" + " signal.signal(signal.SIGINT, signal_handler);\n" + "lldb_setup_sigint_handler();\n" + "del lldb_setup_sigint_handler\n"); #endif } @@ -3106,7 +3106,7 @@ void ScriptInterpreterPythonImpl::AddToSysPath(AddLocation location, statement.append(path); statement.append("\")"); } - PyRun_SimpleString(statement.c_str()); + RunSimpleString(statement.c_str()); } // We are intentionally NOT calling Py_Finalize here (this would be the logical diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 4698b82acb1d1..83b64b85faebd 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -475,7 +475,7 @@ class IOHandlerPythonInterpreter : public IOHandler { StreamString run_string; run_string.Printf("run_python_interpreter (%s)", m_python->GetDictionaryName()); - PyRun_SimpleString(run_string.GetData()); + python::RunSimpleString(run_string.GetData()); } } SetIsDone(true); diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index fbb005b3f0fd3..068860ebc20f1 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -22,7 +22,7 @@ void PythonTestSuite::SetUp() { // test suite. Py_InitializeEx(0); m_gil_state = PyGILState_Ensure(); - PyRun_SimpleString("import sys"); + python::RunSimpleString("import sys"); } void PythonTestSuite::TearDown() {