From 97a62ebef2e6601f6c46a6c38f0a830d1a0145f6 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 5 Apr 2018 11:04:15 -0300 Subject: [PATCH] Add workaround for clang 3.3/3.4 As reported in #1349, clang before 3.5 can segfault on a function-local variable referenced inside a lambda. This moves the function-local static into a separate function that the lambda can invoke to avoid the issue. Fixes #1349 --- include/pybind11/pybind11.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 7723d2a8e..9a5f71a1d 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1631,6 +1631,7 @@ void register_exception_translator(ExceptionTranslator&& translator) { template class exception : public object { public: + exception() = default; exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { std::string full_name = scope.attr("__name__").cast() + std::string(".") + name; @@ -1647,6 +1648,14 @@ public: } }; +NAMESPACE_BEGIN(detail) +// Returns a reference to a function-local static exception object used in the simple +// register_exception approach below. (It would be simpler to have the static local variable +// directly in register_exception, but that makes clang <3.5 segfault - issue #1349). +template +exception &get_exception_object() { static exception ex; return ex; } +NAMESPACE_END(detail) + /** * Registers a Python exception in `m` of the given `name` and installs an exception translator to * translate the C++ exception to the created Python exception using the exceptions what() method. @@ -1657,13 +1666,15 @@ template exception ®ister_exception(handle scope, const char *name, PyObject *base = PyExc_Exception) { - static exception ex(scope, name, base); + auto &ex = detail::get_exception_object(); + if (!ex) ex = exception(scope, name, base); + register_exception_translator([](std::exception_ptr p) { if (!p) return; try { std::rethrow_exception(p); } catch (const CppException &e) { - ex(e.what()); + detail::get_exception_object()(e.what()); } }); return ex;