• Jason Rhinelander's avatar
    Fix builtin exception handlers to work across modules · d5981729
    Jason Rhinelander authored
    The builtin exception handler currently doesn't work across modules
    under clang/libc++ for builtin pybind exceptions like
    `pybind11::error_already_set` or `pybind11::stop_iteration`: under
    RTLD_LOCAL module loading clang considers each module's exception
    classes distinct types.  This then means that the base exception
    translator fails to catch the exceptions and the fall through to the
    generic `std::exception` handler, which completely breaks things like
    `stop_iteration`: only the `stop_iteration` of the first module loaded
    actually works properly; later modules raise a RuntimeError with no
    message when trying to invoke their iterators.
    
    For example, two modules defined like this exhibit the behaviour under
    clang++/libc++:
    
    z1.cpp:
        #include <pybind11/pybind11.h>
        #include <pybind11/stl_bind.h>
        namespace py = pybind11;
        PYBIND11_MODULE(z1, m) {
            py::bind_vector<std::vector<long>>(m, "IntVector");
        }
    
    z2.cpp:
        #include <pybind11/pybind11.h>
        #include <pybind11/stl_bind.h>
        namespace py = pybind11;
        PYBIND11_MODULE(z2, m) {
            py::bind_vector<std::vector<double>>(m, "FloatVector");
        }
    
    Python:
        import z1, z2
        for i in z2.FloatVector():
            pass
    
    results in:
        Traceback (most recent call last):
          File "zs.py", line 2, in <module>
            for i in z2.FloatVector():
        RuntimeError
    
    This commit fixes the issue by adding a new exception translator each
    time the internals pointer is initialized from python builtins: this
    generally means the internals data was initialized by some other
    module.  (The extra translator(s) are skipped under libstdc++).
    d5981729
pybind11_cross_module_tests.cpp 1.12 KB