From cf0a64596ea067f244deb49fa40c402b176a7176 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 18 Aug 2020 07:14:34 -0400 Subject: [PATCH] fix: throwing repr caused a segfault (#2389) * fix: throwing repr caused a segfault * fixup! ci: include Python 3.9 RC1 (#2387) --- include/pybind11/pybind11.h | 13 +++++++++++-- tests/test_exceptions.cpp | 3 +++ tests/test_exceptions.py | 11 +++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d34c92c24..3a7d7b884 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -776,7 +776,11 @@ protected: for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) { if (!some_args) some_args = true; else msg += ", "; - msg += pybind11::repr(args_[ti]); + try { + msg += pybind11::repr(args_[ti]); + } catch (const error_already_set&) { + msg += ""; + } } if (kwargs_in) { auto kwargs = reinterpret_borrow(kwargs_in); @@ -787,7 +791,12 @@ protected: for (auto kwarg : kwargs) { if (first) first = false; else msg += ", "; - msg += pybind11::str("{}={!r}").format(kwarg.first, kwarg.second); + msg += pybind11::str("{}=").format(kwarg.first); + try { + msg += pybind11::repr(kwarg.second); + } catch (const error_already_set&) { + msg += ""; + } } } } diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index 372d0aebf..537819d98 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -218,4 +218,7 @@ TEST_SUBMODULE(exceptions, m) { } }); + // Test repr that cannot be displayed + m.def("simple_bool_passthrough", [](bool x) {return x;}); + } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 83a46bfc8..7d7088d00 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -178,3 +178,14 @@ def test_nested_throws(capture): with pytest.raises(m.MyException5) as excinfo: m.try_catch(m.MyException, pycatch, m.MyException, m.throws5) assert str(excinfo.value) == "this is a helper-defined translated exception" + + +# This can often happen if you wrap a pybind11 class in a Python wrapper +def test_invalid_repr(): + + class MyRepr(object): + def __repr__(self): + raise AttributeError("Example error") + + with pytest.raises(TypeError): + m.simple_bool_passthrough(MyRepr())