diff --git a/newsfragments/4766.fixed.md b/newsfragments/4766.fixed.md new file mode 100644 index 00000000000..3f69e5d5f63 --- /dev/null +++ b/newsfragments/4766.fixed.md @@ -0,0 +1 @@ +Fix unnecessary internal `py.allow_threads` GIL-switch when attempting to access contents of a `PyErr` which originated from Python (could lead to unintended deadlocks). diff --git a/src/err/err_state.rs b/src/err/err_state.rs index 3b9e9800b6e..98be633e91c 100644 --- a/src/err/err_state.rs +++ b/src/err/err_state.rs @@ -43,7 +43,13 @@ impl PyErrState { } pub(crate) fn normalized(normalized: PyErrStateNormalized) -> Self { - Self::from_inner(PyErrStateInner::Normalized(normalized)) + let state = Self::from_inner(PyErrStateInner::Normalized(normalized)); + // This state is already normalized, by completing the Once immediately we avoid + // reaching the `py.allow_threads` in `make_normalized` which is less efficient + // and introduces a GIL switch which could deadlock. + // See https://github.com/PyO3/pyo3/issues/4764 + state.normalized.call_once(|| {}); + state } pub(crate) fn restore(self, py: Python<'_>) {