mirror of
https://github.com/pybind/pybind11.git
synced 2025-01-19 17:32:37 +00:00
Fix handling of Python exceptions during module initialization (#657)
Fixes #656. Before this commit, the problematic sequence was: 1. `catch (const std::exception &e)` gets a Python exception, i.e. `error_already_set`. 2. `PyErr_SetString(PyExc_ImportError, e.what())` sets an `ImportError`. 3. `~error_already_set()` now runs, but `gil_scoped_acquire` fails due to an unhandled `ImportError` (which was just set in step 2). This commit adds a separate catch block for Python exceptions which just clears the Python error state a little earlier and replaces it with an `ImportError`, thus making sure that there is only a single Python exception in flight at a time. (After step 2 in the sequence above, there were effectively two Python expections set.)
This commit is contained in:
parent
1eaacd19f6
commit
d534bd670e
@ -189,6 +189,10 @@ extern "C" {
|
||||
} \
|
||||
try { \
|
||||
return pybind11_init(); \
|
||||
} catch (pybind11::error_already_set &e) { \
|
||||
e.clear(); \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
} catch (const std::exception &e) { \
|
||||
PyErr_SetString(PyExc_ImportError, e.what()); \
|
||||
return nullptr; \
|
||||
@ -561,6 +565,9 @@ public:
|
||||
/// Give the error back to Python
|
||||
void restore() { PyErr_Restore(type, value, trace); type = value = trace = nullptr; }
|
||||
|
||||
/// Clear the held Python error state (the C++ `what()` message remains intact)
|
||||
void clear() { restore(); PyErr_Clear(); }
|
||||
|
||||
private:
|
||||
PyObject *type, *value, *trace;
|
||||
};
|
||||
|
@ -1884,8 +1884,7 @@ class gil_scoped_release { };
|
||||
error_already_set::~error_already_set() {
|
||||
if (value) {
|
||||
gil_scoped_acquire gil;
|
||||
PyErr_Restore(type, value, trace);
|
||||
PyErr_Clear();
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user