[LLDB] Fix Python GIL-not-held issues

The GIL must be held when calling any Python C API functions. In multithreaded applications that use callbacks this requirement can easily be violated by accident. A general tool to ensure GIL health is not available, but patching Python Py_INCREF to add an assert provides a basic health check:

```
+int PyGILState_Check(void); /* Include/internal/pystate.h */
+
 #define Py_INCREF(op) (                         \
+    assert(PyGILState_Check()),                 \
     _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
     ((PyObject *)(op))->ob_refcnt++)

 #define Py_DECREF(op)                                   \
     do {                                                \
+        assert(PyGILState_Check());                     \
         PyObject *_py_decref_tmp = (PyObject *)(op);    \
         if (_Py_DEC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
         --(_py_decref_tmp)->ob_refcnt != 0)             \
```

Adding this assertion causes around 50 test failures in LLDB. Adjusting the scope of things guarded by `py_lock` fixes them.

More background: https://docs.python.org/3/glossary.html#term-global-interpreter-lock

Patch by Ralf Grosse-Kunstleve

Differential Revision: https://reviews.llvm.org/D114722
This commit is contained in:
Ralf Grosse-Kunstleve
2022-01-11 19:34:38 +01:00
committed by Pavel Labath
parent af12a3f4a9
commit a6598575f4
3 changed files with 57 additions and 66 deletions

View File

@@ -88,12 +88,21 @@ public:
StructuredPythonObject() : StructuredData::Generic() {}
StructuredPythonObject(void *obj) : StructuredData::Generic(obj) {
assert(PyGILState_Check());
Py_XINCREF(GetValue());
}
~StructuredPythonObject() override {
if (Py_IsInitialized())
Py_XDECREF(GetValue());
if (Py_IsInitialized()) {
if (_Py_IsFinalizing()) {
// Leak GetValue() rather than crashing the process.
// https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure
} else {
PyGILState_STATE state = PyGILState_Ensure();
Py_XDECREF(GetValue());
PyGILState_Release(state);
}
}
SetValue(nullptr);
}
@@ -264,8 +273,16 @@ public:
~PythonObject() { Reset(); }
void Reset() {
if (m_py_obj && Py_IsInitialized())
Py_DECREF(m_py_obj);
if (m_py_obj && Py_IsInitialized()) {
if (_Py_IsFinalizing()) {
// Leak m_py_obj rather than crashing the process.
// https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure
} else {
PyGILState_STATE state = PyGILState_Ensure();
Py_DECREF(m_py_obj);
PyGILState_Release(state);
}
}
m_py_obj = nullptr;
}