From c3a432d1be64f9b427fb642ec526e8e38190270d Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Fri, 6 Dec 2024 11:00:06 +0000 Subject: [PATCH] eagerly complete once in normalized error state (#4766) * eagerly complete once in normalized error state * newsfragment --- newsfragments/4766.fixed.md | 1 + src/err/err_state.rs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 newsfragments/4766.fixed.md 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<'_>) {