In mjpython, check the result of Py_InitializeFromConfig.

This is to properly handle the case where the interpreter wants to exit immediately, e.g. when `mjpython --version` is run.

Currently, we call `PyGILState_Ensure` regardless of the result of `Py_InitializeFromConfig` resulting in a segfault, as in issue #2870.

PiperOrigin-RevId: 869652555
Change-Id: I3a898279eb8aa25afbaece904cfdcc4fdcc92972
This commit is contained in:
Saran Tunyasuvunakool
2026-02-13 03:43:58 -08:00
committed by Copybara-Service
parent 881544c0c5
commit 496f6b47fc
+18 -3
View File
@@ -57,6 +57,8 @@ struct {
CPYTHON_FN(PyGILState_Ensure); CPYTHON_FN(PyGILState_Ensure);
CPYTHON_FN(PyGILState_Release); CPYTHON_FN(PyGILState_Release);
CPYTHON_FN(PyRun_SimpleStringFlags); CPYTHON_FN(PyRun_SimpleStringFlags);
CPYTHON_FN(PyStatus_Exception);
CPYTHON_FN(Py_ExitStatusException);
CPYTHON_FN(Py_FinalizeEx); CPYTHON_FN(Py_FinalizeEx);
CPYTHON_FN(Py_InitializeFromConfig); CPYTHON_FN(Py_InitializeFromConfig);
CPYTHON_FN(Py_RunMain); CPYTHON_FN(Py_RunMain);
@@ -65,7 +67,7 @@ struct {
#undef CPYTHON_FN #undef CPYTHON_FN
} cpython; } cpython;
std::atomic_bool py_initialized = false; std::atomic_bool py_initialized;
struct Args { struct Args {
int argc; int argc;
@@ -80,8 +82,20 @@ void* mjpython_pymain(void* vargs) {
// Initialize the Python interpreter. // Initialize the Python interpreter.
PyConfig config; PyConfig config;
cpython.PyConfig_InitPythonConfig(&config); cpython.PyConfig_InitPythonConfig(&config);
cpython.PyConfig_SetBytesArgv(&config, args->argc, args->argv); {
cpython.Py_InitializeFromConfig(&config); PyStatus status = cpython.PyConfig_SetBytesArgv(&config, args->argc, args->argv);
if (cpython.PyStatus_Exception(status)) {
// Calls exit() which aborts the entire process.
cpython.Py_ExitStatusException(status);
}
}
{
PyStatus status = cpython.Py_InitializeFromConfig(&config);
if (cpython.PyStatus_Exception(status)) {
// Calls exit() which aborts the entire process.
cpython.Py_ExitStatusException(status);
}
}
cpython.PyConfig_Clear(&config); cpython.PyConfig_Clear(&config);
// Set up the condition variable to pass control back to the macOS main thread. // Set up the condition variable to pass control back to the macOS main thread.
@@ -205,6 +219,7 @@ _mjpython_init()
} // namespace } // namespace
int main(int argc, char** argv) { int main(int argc, char** argv) {
py_initialized.store(false);
const char* libpython_path = getenv("MJPYTHON_LIBPYTHON"); const char* libpython_path = getenv("MJPYTHON_LIBPYTHON");
if (!libpython_path || !libpython_path[0]) { if (!libpython_path || !libpython_path[0]) {
std::cerr << "This binary must be launched via the mjpython.py script.\n"; std::cerr << "This binary must be launched via the mjpython.py script.\n";