[UBSan] Is static linking supported?

The address sanitizer is documented as not supported with static linking, but UBSan does not include the same disclaimer. UBSan does not work for me with statically-linked executables. Instead, the executables segfault immediately when attempting to install signal handlers. Is this expected?

-Troy

On some platforms it's possible to statically link against the ASan/UBSan runtimes using the undocumented -static-libsan option. The default behavior on Darwin, Android, and Fuchsia is to link against a DSO.

The address sanitizer is documented as not supported with static linking, but UBSan does not include the same disclaimer. UBSan does not work for me with statically-linked executables. Instead, the executables segfault immediately when attempting to install signal handlers. Is this expected?

No, that's not expected :). Could you share the options you used to compile and link it, and the backtrace you get?

vedant

According to Reid Kleckner over on llvm-dev sanitizers will not work at
all with a statically-linked libc, as the interceptors use dlsym to set
up calls to sigaction and the like. That matched my findings while
debugging the problem we're seeing. If sanitizers are supposed to work
with static linking, then it seems like the dependence on dlsym needs to
be broken.

Otherwise, the sanitizers should catch a nullptr return value from dlsym
and report a friendly user error message. I can write a patch to do
that if it seems like a good idea. Even when linking dynamically, it
would be good to check the return value of dlsym and report the error to
the user.

                           -David

Vedant Kumar via cfe-dev <cfe-dev@lists.llvm.org> writes:

According to Reid Kleckner over on llvm-dev sanitizers will not work at
all with a statically-linked libc, as the interceptors use dlsym to set
up calls to sigaction and the like. That matched my findings while
debugging the problem we're seeing.

Good point, that might be the issue here.

If sanitizers are supposed to work
with static linking, then it seems like the dependence on dlsym needs to
be broken.

Otherwise, the sanitizers should catch a nullptr return value from dlsym
and report a friendly user error message. I can write a patch to do
that if it seems like a good idea. Even when linking dynamically, it
would be good to check the return value of dlsym and report the error to
the user.

+ 1.

vedant

According to Reid Kleckner over on llvm-dev sanitizers will not work at
all with a statically-linked libc, as the interceptors use dlsym to set
up calls to sigaction and the like. That matched my findings while
debugging the problem we’re seeing.

Good point, that might be the issue here.

UBSan, unlike the other sanitizers, was explicitly designed to not perform any interception. It’s possible that has changed in the interim, of course …

According to Reid Kleckner over on llvm-dev sanitizers will not work at
all with a statically-linked libc, as the interceptors use dlsym to set
up calls to sigaction and the like. That matched my findings while
debugging the problem we’re seeing.

Good point, that might be the issue here.

UBSan, unlike the other sanitizers, was explicitly designed to not perform any interception. It’s possible that has changed in the interim, of course …

Ah, you’re right, I don’t think that’s changed.

The standalone version of the UBSan runtime used on Windows does install its own signal handlers. Maybe that causes a bad interaction with Troy’s program?

vedant

Standalone ubsan has a few interceptors to handle signals - in
particular, handle_segv=2 (and others) blocks the user program from
replacing the signal handler. Ignoring return value of 0 from dlsym
would not work, because then the libc sigaction() is unreachable.

I wonder if there should be a separate version of the runtime library
for use with fully static binaries?

> The standalone version of the UBSan runtime used on Windows does
> install its own signal handlers. Maybe that causes a bad interaction
> with Troy's program?

I was running on Linux, not Windows.

>> >> No, that's not expected :). Could you share the options you used
>> >> to compile and link it, and the backtrace you get?

I was trying the test.cc example here: UndefinedBehaviorSanitizer — Clang 18.0.0git documentation

But with the addition of -static. It linked, but immediately seg faulted when I ran it.

Notably, if you try -static with another sanitizer, like -fsanitize=address, you get linker errors with the word "dynamic" in it, so it becomes pretty clear that you are doing something unexpected.

The successful link of -fsanitize=undefined -static plus the lack of any disclaimer in the documentation made me assume it should work.

-Troy

[ Trying to unify these two threads. ]

I am unsure of how we should proceed. I was about to prepare a patch to
test for a nullptr return value from dlsym and emit a helpful error
message to the user. That may still be useful as dlsym could still
return nullptr even in a dynamically-linked executable.

But it sounds like some more work needs to be done on UBSan to make it
work with static binaries again.

Is the nullptr check patch still desired? If so, is there any reason to
delay it until other issues with UBSan can be worked out?

                          -David

Troy Johnson via cfe-dev <cfe-dev@lists.llvm.org> writes: