llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.31k stars 11.69k forks source link

Extend clang to link C code with C++ libraries, that are compiled with -fsanitize=undefined #45293

Open llvmbot opened 4 years ago

llvmbot commented 4 years ago
Bugzilla Link 45948
Version 10.0
OS Linux
Reporter LLVM Bugzilla Contributor

Extended Description

I create a file d.cpp:

struct D { bool d; };

struct E : virtual D { int e; };

extern "C" { void f(); }

void f() { D g = E(); };

and compile it with clang 10.0 $ clang++ -fsanitize=undefined -shared -fpic -o libd.so d.cpp

Then I create a file h.c: void f(); int main() { f(); return 0; } and compile it with: $ clang -fsanitize=undefined -L. -ld h.c /usr/local/bin/ld: ./libd.so: undefined reference to __ubsan_vptr_type_cache' /usr/local/bin/ld: ./libd.so: undefined reference to__ubsan_handle_dynamic_type_cache_miss' clang-10: error: linker command failed with exit code 1 (use -v to see invocation)

If I use instead $ clang -fsanitize=undefined -L. -ld h.c -lubsan then it magically works. But libubsan is from gcc, sometimes does not contain the symbols that clang emits and UBSAN is not supposed to work this way.

If I take instead j.cpp: extern "C" { void f(); }

int main() { f(); return 0; }

then $ clang++ -fsanitize=undefined -L. -ld j.cpp does work. If I put in h.c the f() declarition withing extern "C" {}, then $ clang++ -fsanitize=undefined -L. -ld h.c clang-10: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]

works somehow.

If I use: $ clang -fsanitize=undefined -c -o h.o h.c $ clang++ -fsanitize=undefined h.o -L. -ld -o h then it also works, but build tools do not know that they cannot short-circuit to $ clang -fsanitize=undefined -o h -L. -ld h.c

https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#usage says for Clang 11 (I use 10): “Use clang++ to compile and link your program with -fsanitize=undefined flag. … You can use clang instead of clang++ if you’re compiling/linking C code.”

Now, I am compiling C code, but linking it with C++ code. There are real-world use cases: ICU and WebKIT are in C++, but can be used from C code. So to verify the whole linking C code using clang, with C++ libraries must also work.

See also https://sourceware.org/bugzilla/show_bug.cgi?id=25940 .

⇒ Enhance clang -fsanitize=undefined -ld to link with the d-library, even when that library is in C++ and was compiled with clang++ -fsanitize=undefined.

ddassie-texa commented 1 day ago

I have just encountered this issue when linking a C++ library to a C program, both having ubsan enabled, linker error:

[24/25] Linking C executable examples/Debug/ReferenceApp
FAILED: examples/Debug/ReferenceApp 
: && /usr/bin/clang -g -fsanitize=address,leak,undefined -Wall -Wextra -Wshadow -Wcast-align -Wunused -Wpedantic -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wimplicit-fallthrough -Werror examples/CMakeFiles/ReferenceApp.dir/Debug/main.c.o -o examples/Debug/ReferenceApp  -Wl,-rpath,/tmp/9512b82f-d185-50ea-ee23-d010bc14782f/build/clang/example/Debug  example/Debug/libexampled.so.0.1.0  --coverage && :
/usr/bin/ld: example/Debug/libexampled.so.0.1.0: undefined reference to `__ubsan_vptr_type_cache'
/usr/bin/ld: example/Debug/libexampled.so.0.1.0: undefined reference to `__ubsan_handle_dynamic_type_cache_miss'
clang: error: linker command failed with exit code 1 (use -v to see invocation)