Cpp2 exceptions

As far as I understand the unit tests, it is expected that PL_get_nchars fails in some of them (and raises a representation error).

test(hello, error(representation_error(encoding))) :-
    hello("世界", _Out).

Yes, that test is designed to get an error. because “世界” can’t be represented in ASCII.

Except, I can’t reproduce the error (see clang.asan: unit tests fail · Issue #102 · SWI-Prolog/packages-cpp · GitHub) but instead shows up in clib:crypt for gcc-12, clang-14, but not clang-19. (I used ctest j=1 to ensure the tests were isolated from each other, although that probably wasn’t necessary). PlTerm::get_nchars() uses PlEx_fail() to check whether the “false” return code from PL_get_nchars() is simply a failure or is an error (from reading the code, it seems that only a representation error is possible, but there might be other error possibilities).

Unsure if this helps (maybe on the longer run), but I can reproduce this problem also in a minimalistic example:

example.cpp:

#include <SWI-cpp2.h>

PREDICATE(helloex, 0)
{ throw PlUnknownError("an exception");
}

Compile with src/swipl-ld -g -shared example.cpp -o example.so, then
use_foreign_library(example). helloex.

(cmake configuration as above)

CC="clang-21 -fsanitize=address,undefined -fno-sanitize=float-divide-by-zero -fno-sanitize=alignment -fno-sanitize=function -fno-omit-frame-pointer -std=gnu23" CXX="clang++-21 -fsanitize=address,undefined -fno-sanitize=float-divide-by-zero -fno-sanitize=alignment -fno-omit-frame-pointer -frtti -std=gnu++17" CFLAGS="-g -O3 -Wall " LDFLAGS="-Wl,-O1" CXXFLAGS="-g -O3 -Wall -pedantic  -fpic" cmake -DCMAKE_CXX_STANDARD=17 -DCMAKE_INSTALL_PREFIX=~/swipl -DMACOSX_DEPENDENCIES_FROM=Homebrew -DSWIPL_INSTALL_IN_LIB=ON -DINSTALL_DOCUMENTATION=OFF -DBUILD_TESTING=ON -DINSTALL_TESTS=ON -DSWIPL_PACKAGES_JAVA=OFF -DSWIPL_PACKAGES_GUI=OFF -DSWIPL_PACKAGES_ODBC=OFF -DSWIPL_PACKAGES_PYTHON=OFF -S ..
make

Did you set this up with scripts/configure? If so, what is the build directory name (with the options)?

I’ll add this trivial test to the cpp tests.

No, with the cmake command shown. I’ll try to simplify this during the day, so that it matches the build.make.clang etc logic

Simpler version:

cd swipl-devel
mkdir build.make.clang\=21.asan
cd build.make.clang\=21.asan
../scripts/configure
make
src/swipl-ld -g -shared example.cpp -o example.so
src/swipl
?- use_foreign_library(example).
?- helloex.

Needs clang-21, of course.

It can also be reproduced with with gcc (15.2.0 on my computer):

cd swipl-devel
mkdir build.make.gcc.asan
cd build.make.gcc.asan
../scripts/configure
make
src/swipl-ld -g -shared example.cpp -o example.so
src/swipl
?- use_foreign_library(example).
?- helloex.

It seems that I can, well, “fix” the problem with

LD_PRELOAD="$(realpath "$(gcc -print-file-name=libasan.so)") $(realpath "$(gcc -print-file-name=libstdc++.so)")" ctest

so that it is rather a linker problem. See discussion of a similar problem here. AddressSanitizer CHECK failed: ../../../sanitizer/asan/asan_interceptors.cc:384 "((__interception::real___cxa_throw)) when using --as-needed and dynamically loaded .so · Issue #934 · google/sanitizers · GitHub

Needless to say that I have no idea what all this stuff is about.

Edit:

LD_PRELOAD=$(gcc -print-file-name=libstdc++.so) ctest

works, too, if we add -DCMAKE_BUILD_TYPE=Sanitize.

I think I’ve encountered a similar problem in the past that was solved with LD_PRELOAD … I forget the details but I think it was something to do with an executable requiring one path for its shared libraries but ASAN requiring a different path; and therefore the runtime ASAN library doesn’t match what the executable was built with. (So, this is something that static linking would probably solve)

I’ll see if I have any notes from this and if there’s a better solution (it was years ago).

Anyway, it appears that the crash is due to an ASAN shared library problem and not due to a bug in either the SWI-cpp API or some subtlety in C++ exceptions.