Fix exception handling when pybind11::weakref() fails. (#3739)

* Clear Python error state if pybind11::weakref() fails.

The weakref() constructor calls pybind11_fail() without clearing any
Python interpreter error state. If a client catches the C++ exception
thrown by pybind11_fail(), the Python interpreter will be left in an
error state.

* Add test case for failing to create weakref

* Add Debug asserts for pybind11 fail

* Make error handling more pythonic

* Does this fix PyPy?

* Adapt test to PyPy differences

* Simplify test to remove redundancy

Co-authored-by: Aaron Gokaslan <skylion.aaron@gmail.com>
This commit is contained in:
Peter Hawkins
2022-02-18 14:12:00 -05:00
committed by GitHub
parent 009ffc3362
commit 44596bc4ee
3 changed files with 32 additions and 1 deletions

View File

@@ -936,9 +936,11 @@ PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybin
PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) {
assert(!PyErr_Occurred());
throw std::runtime_error(reason);
}
[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) {
assert(!PyErr_Occurred());
throw std::runtime_error(reason);
}

View File

@@ -1509,6 +1509,9 @@ public:
explicit weakref(handle obj, handle callback = {})
: object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {
if (!m_ptr) {
if (PyErr_Occurred()) {
throw error_already_set();
}
pybind11_fail("Could not allocate weak reference!");
}
}