Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[driver] Fix sanitizer libc++ runtime linking #120370

Merged

Conversation

vitalybuka
Copy link
Collaborator

@vitalybuka vitalybuka commented Dec 18, 2024

  1. -f[no-]sanitize-link-c++-runtime suppose to
    override defauld behavior implied from CCCIsCXX
  2. Take into account -nostdlib++ (unblocks [runtimes] Probe for -nostdlib++ and -nostdinc++ with the C compiler #108357)
  3. Fix typo hasFlag vs hasArg.

Created using spr 1.3.4
@llvmbot llvmbot added clang Clang issues not falling into any other category compiler-rt clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' compiler-rt:hwasan Hardware-assisted address sanitizer compiler-rt:sanitizer labels Dec 18, 2024
@vitalybuka vitalybuka requested a review from MaskRay December 18, 2024 07:11
@llvmbot
Copy link
Member

llvmbot commented Dec 18, 2024

@llvm/pr-subscribers-compiler-rt-sanitizer
@llvm/pr-subscribers-clang-driver

@llvm/pr-subscribers-clang

Author: Vitaly Buka (vitalybuka)

Changes
  1. -f[no-]sanitize-link-c++-runtime suppose to
    override defauld behavior implied from CCCIsCXX
  2. Take into account -nostdlib++
  3. Fix typo hasFlag vs hasArg.

Full diff: https://github.com/llvm/llvm-project/pull/120370.diff

3 Files Affected:

  • (modified) clang/lib/Driver/SanitizerArgs.cpp (+5-4)
  • (modified) clang/test/Driver/sanitizer-ld.c (+64-1)
  • (modified) compiler-rt/test/hwasan/TestCases/sizes.cpp (+1-1)
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 81f94f23873661..0edfe641416129 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -1098,10 +1098,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
                    options::OPT_fno_sanitize_link_runtime, LinkRuntimes);
 
   // Parse -link-cxx-sanitizer flag.
-  LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime,
-                                options::OPT_fno_sanitize_link_cxx_runtime,
-                                LinkCXXRuntimes) ||
-                    D.CCCIsCXX();
+  LinkCXXRuntimes =
+      D.CCCIsCXX() && !Args.hasArg(clang::driver::options::OPT_nostdlibxx);
+  LinkCXXRuntimes =
+      Args.hasFlag(options::OPT_fsanitize_link_cxx_runtime,
+                   options::OPT_fno_sanitize_link_cxx_runtime, LinkCXXRuntimes);
 
   NeedsMemProfRt = Args.hasFlag(options::OPT_fmemory_profile,
                                 options::OPT_fmemory_profile_EQ,
diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c
index 60d60a6047b0f4..6ab1adf401ae0a 100644
--- a/clang/test/Driver/sanitizer-ld.c
+++ b/clang/test/Driver/sanitizer-ld.c
@@ -132,7 +132,14 @@
 // RUN:     -resource-dir=%S/Inputs/empty_resource_dir \
 // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
 // RUN:   | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s
-//
+
+// RUN: %clangxx -### %s 2>&1 \
+// RUN:     --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \
+// RUN:     -resource-dir=%S/Inputs/empty_resource_dir \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:     -fsanitize-link-c++-runtime \
+// RUN:   | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s
+
 // CHECK-ASAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
 // CHECK-ASAN-LINUX-CXX-NOT: "-lc"
 // CHECK-ASAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive"
@@ -145,6 +152,62 @@
 // CHECK-ASAN-LINUX-CXX: "-ldl"
 // CHECK-ASAN-LINUX-CXX: "-lresolv"
 
+// RUN: %clang -### %s 2>&1 \
+// RUN:     --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \
+// RUN:     -resource-dir=%S/Inputs/empty_resource_dir \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:     -fno-sanitize-link-c++-runtime \
+// RUN:   | FileCheck --check-prefix=CHECK-ASAN-LINUX-CNOCXX %s
+
+// CHECK-ASAN-LINUX-CNOCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-CNOCXX-NOT: "-lc"
+// CHECK-ASAN-LINUX-CNOCXX: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive"
+// CHECK-ASAN-LINUX-CNOCXX-NOT: libclang_rt.asan_cxx
+// CHECK-ASAN-LINUX-CNOCXX-NOT: "--dynamic-list"
+// CHECK-ASAN-LINUX-CNOCXX: "--export-dynamic"
+// CHECK-ASAN-LINUX-CNOCXX-NOT: stdc++
+// CHECK-ASAN-LINUX-CNOCXX: "-lpthread"
+// CHECK-ASAN-LINUX-CNOCXX: "-lrt"
+// CHECK-ASAN-LINUX-CNOCXX: "-ldl"
+// CHECK-ASAN-LINUX-CNOCXX: "-lresolv"
+
+// RUN: %clangxx -### %s 2>&1 \
+// RUN:     --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \
+// RUN:     -resource-dir=%S/Inputs/empty_resource_dir \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:     -fno-sanitize-link-c++-runtime \
+// RUN:   | FileCheck --check-prefix=CHECK-ASAN-LINUX-NOCXX %s
+
+// CHECK-ASAN-LINUX-NOCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-NOCXX-NOT: "-lc"
+// CHECK-ASAN-LINUX-NOCXX: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive"
+// CHECK-ASAN-LINUX-NOCXX-NOT: libclang_rt.asan_cxx
+// CHECK-ASAN-LINUX-NOCXX-NOT: "--dynamic-list"
+// CHECK-ASAN-LINUX-NOCXX: "--export-dynamic"
+// CHECK-ASAN-LINUX-NOCXX: stdc++
+// CHECK-ASAN-LINUX-NOCXX: "-lpthread"
+// CHECK-ASAN-LINUX-NOCXX: "-lrt"
+// CHECK-ASAN-LINUX-NOCXX: "-ldl"
+// CHECK-ASAN-LINUX-NOCXX: "-lresolv"
+
+// RUN: %clangxx -### %s 2>&1 \
+// RUN:     --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform -fsanitize=address \
+// RUN:     -resource-dir=%S/Inputs/empty_resource_dir \
+// RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+// RUN:     -nostdlib++ \
+// RUN:   | FileCheck --check-prefix=CHECK-ASAN-LINUX-NOSTDCXX %s
+
+// CHECK-ASAN-LINUX-NOSTDCXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-NOSTDCXX-NOT: "-lc"
+// CHECK-ASAN-LINUX-NOSTDCXX: "--whole-archive" "{{.*}}libclang_rt.asan.a" "--no-whole-archive"
+// CHECK-ASAN-LINUX-NOSTDCXX-NOT: libclang_rt.asan_cxx
+// CHECK-ASAN-LINUX-NOSTDCXX-NOT: "--dynamic-list"
+// CHECK-ASAN-LINUX-NOSTDCXX: "--export-dynamic"
+// CHECK-ASAN-LINUX-NOSTDCXX: "-lpthread"
+// CHECK-ASAN-LINUX-NOSTDCXX: "-lrt"
+// CHECK-ASAN-LINUX-NOSTDCXX: "-ldl"
+// CHECK-ASAN-LINUX-NOSTDCXX: "-lresolv"
+
 // RUN: %clang -### %s -o /dev/null -fsanitize=address \
 // RUN:     --target=i386-unknown-linux -fuse-ld=ld -stdlib=platform \
 // RUN:     -resource-dir=%S/Inputs/resource_dir \
diff --git a/compiler-rt/test/hwasan/TestCases/sizes.cpp b/compiler-rt/test/hwasan/TestCases/sizes.cpp
index ce2c4579d66f61..5bc281e588a99f 100644
--- a/compiler-rt/test/hwasan/TestCases/sizes.cpp
+++ b/compiler-rt/test/hwasan/TestCases/sizes.cpp
@@ -1,6 +1,6 @@
 // This test requires operator new to be intercepted by the hwasan runtime,
 // so we need to avoid linking against libc++.
-// RUN: %clangxx_hwasan %s -nostdlib++ -lstdc++ -o %t || %clangxx_hwasan %s -o %t
+// RUN: %clangxx_hwasan %s -nostdlib++ -lstdc++ -fsanitize-link-c++-runtime -o %t || %clangxx_hwasan %s -o %t
 // RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1          | FileCheck %s --check-prefix=CHECK-max
 // RUN: %env_hwasan_opts=allocator_may_return_null=1     %run %t malloc 2>&1
 // RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t malloc max 2>&1      | FileCheck %s --check-prefix=CHECK-max

Created using spr 1.3.4
@vitalybuka vitalybuka merged commit 9af5de3 into main Dec 18, 2024
4 of 6 checks passed
@vitalybuka vitalybuka deleted the users/vitalybuka/spr/driver-fix-sanitizer-libc-runtime-linking branch December 18, 2024 18:37
thurstond added a commit that referenced this pull request Dec 19, 2024
This reverts commit 9af5de3.

Reason: buildbot breakage
(https://lab.llvm.org/buildbot/#/builders/24/builds/3394/steps/10/logs/stdio)
"Unexpectedly Passed Tests (1):
   llvm-libc++-shared.cfg.in :: libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp"
@mstorsjo
Copy link
Member

This was reverted, because https://github.com/llvm/llvm-project/blob/main/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp in libc++ started passing unexpectedly.

I'm not entirely sure about why that is though - previously, it used to fail like this:

/home/martin/clang-trunk/bin/clang++ /home/martin/code/llvm-project/libcxx/test/
libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp -pthread --targ
et=x86_64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsanitize=address -nostd
inc++ -I /home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/test-suit
e-install/include/c++/v1 -I /home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/test-suite-install/include/c++/v1 -I /home/martin/code/llvm-project/li
bcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wsh
adow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno-attributes
 -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-mo
dule-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wno-user-defined-liter
als -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-paramete
r -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wn
o-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-new-del
ete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_
LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE 
-Werror=thread-safety -Wuser-defined-warnings  -lc++experimental -nostdlib++ -L 
/home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/test-suite-install
/lib -Wl,-rpath,/home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/te
st-suite-install/lib -lc++ -latomic -o /home/martin/code/llvm-project/build-libc
xx-sanitizers/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe -faligned-allocation -fsized-deallocation
# executed command: /home/martin/clang-trunk/bin/clang++ /home/martin/code/llvm-
project/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh
.cpp -pthread --target=x86_64-unknown-linux-gnu -g -fno-omit-frame-pointer -fsan
itize=address -nostdinc++ -I /home/martin/code/llvm-project/build-libcxx-sanitiz
ers/libcxx/test-suite-install/include/c++/v1 -I /home/martin/code/llvm-project/b
uild-libcxx-sanitizers/libcxx/test-suite-install/include/c++/v1 -I /home/martin/
code/llvm-project/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsu
pported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argu
ment -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignm
ent -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecated-copy-dtor -Wn
o-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variab
le -Wunused-parameter -Wunreachable-code -Wno-unused-local-typedef -Wno-local-ty
pe-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wn
o-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAG
MA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MODE=_LIBCPP_
HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings -lc++experimen
tal -nostdlib++ -L /home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx
/test-suite-install/lib -Wl,-rpath,/home/martin/code/llvm-project/build-libcxx-s
anitizers/libcxx/test-suite-install/lib -lc++ -latomic -o /home/martin/code/llvm
-project/build-libcxx-sanitizers/libcxx/test/libcxx/language.support/support.dyn
amic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe -faligned-allocation -fsized-deallocation
# RUN: at line 25
/usr/bin/python3 /home/martin/code/llvm-project/libcxx/utils/run.py --execdir /h
ome/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/test/libcxx/language
.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir --  /home/martin/co
de/llvm-project/build-libcxx-sanitizers/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe
# executed command: /usr/bin/python3 /home/martin/code/llvm-project/libcxx/utils
/run.py --execdir /home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/
test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir
 -- /home/martin/code/llvm-project/build-libcxx-sanitizers/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe
# .---command stderr------------
# | =================================================================
# | ==2987905==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new vs free) on 0x6d15b6e20010
# |     #0 0x5b56d8dee976  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0xcf976)
# |     #1 0x5b56d8e34578  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x115578)
# |     #2 0x5b56d8e34c0c  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x115c0c)
# |     #3 0x5b56d8e34e3f  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x115e3f)
# |     #4 0x70f5b7c2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
# |     #5 0x70f5b7c2a28a  (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
# |     #6 0x5b56d8d4c3d4  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x2d3d4)
# |
# | 0x6d15b6e20010 is located 0 bytes inside of 4-byte region [0x6d15b6e20010,0x6d15b6e20014)
# | allocated by thread T0 here:
# |     #0 0x5b56d8e3205d  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x11305d)
# |     #1 0x5b56d8e34b76  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x115b76)
# |     #2 0x5b56d8e34e3f  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x115e3f)
# |     #3 0x70f5b7c2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
# |     #4 0x70f5b7c2a28a  (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
# |     #5 0x5b56d8d4c3d4  (/home/martin/code/llvm-project/build-libcxx-sanitize
rs/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0x2d3d4)
# |
# | SUMMARY: AddressSanitizer: alloc-dealloc-mismatch (/home/martin/code/llvm-pr
oject/build-libcxx-sanitizers/libcxx/test/libcxx/language.support/support.dynamic/Output/libcpp_deallocate.sh.cpp.dir/t.tmp.exe+0xcf976)
# | ==2987905==HINT: if you don't care about these errors you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
# | ==2987905==ABORTING
# `-----------------------------
# error: command failed with exit status: 1

But after this change, it succeeds.

If this is right and expected that it fixes the root cause, we could change the XFAIL into UNSUPPORTED in that test, while versions both with and without the fix are supported, and then finally remove the UNSUPPORTED later.

But as @vitalybuka mentioned in #108357 (comment), many also expect to be able to link with -nostdlib++ -lc++ and still have working sanitizers (e.g. ubsan, which also failed), which this does break.

vitalybuka added a commit that referenced this pull request Dec 19, 2024
…20538)

Reland without item 2 from #120370 to avoid breaking libc++ tests.

This reverts commit 60a2f32.
vitalybuka added a commit that referenced this pull request Dec 24, 2024
Linking this runtime requires C++ ABI, which breaks -nostdlib++ builds.
However, UBSAN C++ runtime is only needed for CFI and VPTR checks.

Unblocks #120370.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category compiler-rt:hwasan Hardware-assisted address sanitizer compiler-rt:sanitizer compiler-rt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants