Skip to content

[BUG] register_exception_translator have different behaviour when building with different STL. #2847

@oraluben

Description

@oraluben

Issue description

If I have a module a who have an exception translator and module b who throws an exception,
and import a, b in order in another python module.

With libstdc++, when b throws an error, it will be catched by the registered translator,
while with libc++, it won't.

Output1:

+ python -c 'import foo; foo.bar.thr()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
RuntimeError

Output2:

+ python -c 'import foo; foo.bar.thr()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
KeyError: ''

See below for detailed information.

Reproducible example code

This repro requires additional dependencies. I recommend you run it from a docker container (debian:buster has been verified to work).

Install dependencies

#!/bin/sh
set -ex

apt-get update

apt-get install -y -qq python-dev libc++1 libc++-dev pybind11-dev g++
ln -s /usr/lib/llvm-7/lib/libc++abi.so.1 /usr/lib/llvm-7/lib/libc++abi.so || true

Generate test files

#!/bin/sh
set -ex

cat > foo.h <<EOF
#include <stdexcept>

struct e : public std::runtime_error {
    explicit e(const char* what) :
        std::runtime_error(what) {
    }
};
EOF

cat > foo.cc <<EOF
#include <pybind11/pybind11.h>

#include "foo.h"

namespace py = pybind11;

PYBIND11_MODULE(_foo, m) {
    py::register_exception_translator([](std::exception_ptr p) {
        try {
            if (p) std::rethrow_exception(p);
        } catch (const e &_e) {
            PyErr_SetString(PyExc_KeyError, _e.what());
        }
    });
};
EOF

cat > bar.cc <<EOF
#include <pybind11/pybind11.h>

#include "foo.h"

void thr() {
    throw e{""};
}

namespace py = pybind11;

PYBIND11_MODULE(bar, m)
{
    m.def("thr", &thr);
}
EOF

cat > foo.py <<EOF
import _foo

import bar
EOF

Build and run

#!/bin/sh
set -ex

# https://libcxx.llvm.org/docs/UsingLibcxx.html

g++ -I/usr/include/pybind11/ -I/usr/include/python2.7 \
-nostdinc++ -I/usr/lib/llvm-7/include/c++/v1 \
-fPIC -fvisibility=hidden -flto -fno-fat-lto-objects -std=gnu++11 \
-o bar.o -c bar.cc

g++ -fPIC \
-nostdinc++ -I/usr/lib/llvm-7/include/c++/v1 \
-flto -shared \
-nodefaultlibs -L/usr/lib/llvm-7/lib -lc++ -lc++abi -lm -lc -lgcc_s -lgcc \
-o bar.so bar.o

g++ -I/usr/include/pybind11/ -I/usr/include/python2.7 \
-nostdinc++ -I/usr/lib/llvm-7/include/c++/v1 \
-fPIC -fvisibility=hidden -flto -fno-fat-lto-objects -std=gnu++11 \
-o _foo.o -c foo.cc

g++ -fPIC \
-nostdinc++ -I/usr/lib/llvm-7/include/c++/v1 \
-flto -shared \
-nodefaultlibs -L/usr/lib/llvm-7/lib -lc++ -lc++abi -lm -lc -lgcc_s -lgcc \
-o _foo.so _foo.o

python -c "import foo; foo.bar.thr()" || true


g++ -I/usr/include/pybind11/ -I/usr/include/python2.7 \
-fPIC -fvisibility=hidden -flto -fno-fat-lto-objects -std=gnu++11 \
-o bar.o -c bar.cc

g++ -fPIC \
-flto -shared \
-o bar.so bar.o

g++ -I/usr/include/pybind11/ -I/usr/include/python2.7 \
-fPIC -fvisibility=hidden -flto -fno-fat-lto-objects -std=gnu++11 \
-o _foo.o -c foo.cc

g++ -fPIC \
-flto -shared \
-o _foo.so _foo.o

python -c "import foo; foo.bar.thr()" || true

rm -rf *.o *.so

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions