Skip to content

Commit cff3cde

Browse files
committed
Split ubsan runtime into three pieces (clang part):
* libclang_rt-san-* is sanitizer_common, and is linked in only if no other sanitizer runtime is present. * libclang_rt-ubsan-* is the piece of the runtime which doesn't depend on a C++ ABI library, and is always linked in. * libclang_rt-ubsan_cxx-* is the piece of the runtime which depends on a C++ ABI library, and is only linked in when linking a C++ binary. This change also switches us to using -whole-archive for the ubsan runtime (which is made possible by the above split), and switches us to only linking the sanitizer runtime into the main binary and not into DSOs (which is made possible by using -whole-archive). The motivation for this is to only link a single copy of sanitizer_common into any binary. This is becoming important now because we want to share more state between multiple sanitizers in the same process (for instance, we want a single shared output mutex). The Darwin ubsan runtime is unchanged; because we use a DSO there, we don't need this complexity. llvm-svn: 177605
1 parent 71738ca commit cff3cde

File tree

3 files changed

+79
-20
lines changed

3 files changed

+79
-20
lines changed

clang/lib/Driver/Tools.cpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,21 +1582,21 @@ static void addSanitizerRTLinkFlagsLinux(
15821582
llvm::sys::path::append(
15831583
LibSanitizer, "lib", "linux",
15841584
(Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a"));
1585+
15851586
// Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
15861587
// etc.) so that the linker picks custom versions of the global 'operator
15871588
// new' and 'operator delete' symbols. We take the extreme (but simple)
15881589
// strategy of inserting it at the front of the link command. It also
15891590
// needs to be forced to end up in the executable, so wrap it in
15901591
// whole-archive.
1591-
if (BeforeLibStdCXX) {
1592-
SmallVector<const char *, 3> PrefixArgs;
1593-
PrefixArgs.push_back("-whole-archive");
1594-
PrefixArgs.push_back(Args.MakeArgString(LibSanitizer));
1595-
PrefixArgs.push_back("-no-whole-archive");
1596-
CmdArgs.insert(CmdArgs.begin(), PrefixArgs.begin(), PrefixArgs.end());
1597-
} else {
1598-
CmdArgs.push_back(Args.MakeArgString(LibSanitizer));
1599-
}
1592+
SmallVector<const char *, 3> LibSanitizerArgs;
1593+
LibSanitizerArgs.push_back("-whole-archive");
1594+
LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer));
1595+
LibSanitizerArgs.push_back("-no-whole-archive");
1596+
1597+
CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
1598+
LibSanitizerArgs.begin(), LibSanitizerArgs.end());
1599+
16001600
CmdArgs.push_back("-lpthread");
16011601
CmdArgs.push_back("-ldl");
16021602
CmdArgs.push_back("-export-dynamic");
@@ -1658,8 +1658,22 @@ static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
16581658
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
16591659
/// (Linux).
16601660
static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
1661-
ArgStringList &CmdArgs) {
1661+
ArgStringList &CmdArgs, bool IsCXX,
1662+
bool HasOtherSanitizerRt) {
1663+
if (Args.hasArg(options::OPT_shared))
1664+
return;
1665+
1666+
// Need a copy of sanitizer_common. This could come from another sanitizer
1667+
// runtime; if we're not including one, include our own copy.
1668+
if (!HasOtherSanitizerRt)
1669+
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true);
1670+
16621671
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false);
1672+
1673+
// Only include the bits of the runtime which need a C++ ABI library if
1674+
// we're linking in C++ mode.
1675+
if (IsCXX)
1676+
addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false);
16631677
}
16641678

16651679
static bool shouldUseFramePointer(const ArgList &Args,
@@ -5876,7 +5890,9 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
58765890

58775891
// Call these before we add the C++ ABI library.
58785892
if (Sanitize.needsUbsanRt())
5879-
addUbsanRTLinux(getToolChain(), Args, CmdArgs);
5893+
addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX,
5894+
Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
5895+
Sanitize.needsMsanRt());
58805896
if (Sanitize.needsAsanRt())
58815897
addAsanRTLinux(getToolChain(), Args, CmdArgs);
58825898
if (Sanitize.needsTsanRt())

clang/runtime/compiler-rt/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,21 +99,23 @@ TryCompile = \
9999
# We currently only try to generate runtime libraries on x86.
100100
ifeq ($(ARCH),x86)
101101
RuntimeLibrary.linux.Configs += \
102-
full-i386.a profile-i386.a asan-i386.a ubsan-i386.a
102+
full-i386.a profile-i386.a san-i386.a asan-i386.a ubsan-i386.a \
103+
ubsan_cxx-i386.a
103104
endif
104105

105106
ifeq ($(ARCH),x86_64)
106107
RuntimeLibrary.linux.Configs += \
107-
full-x86_64.a profile-x86_64.a asan-x86_64.a tsan-x86_64.a msan-x86_64.a \
108-
ubsan-x86_64.a
108+
full-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \
109+
tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a
109110
# We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them
110111
# to the list of runtime libraries to make
111112
# "clang -fsanitize=(address|undefined) -m32" work.
112113
# We check that Clang can produce working 32-bit binaries by compiling a simple
113114
# executable.
114115
test_source = $(LLVM_SRC_ROOT)/tools/clang/runtime/compiler-rt/clang_linux_test_input.c
115116
ifeq ($(call TryCompile,$(ToolDir)/clang,$(test_source),-m32),0)
116-
RuntimeLibrary.linux.Configs += asan-i386.a ubsan-i386.a
117+
RuntimeLibrary.linux.Configs += san-i386.a asan-i386.a ubsan-i386.a \
118+
ubsan_cxx-i386.a
117119
endif
118120
ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
119121
RuntimeLibrary.linux.Configs += asan-arm-android.so

clang/test/Driver/sanitizer-ld.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,57 @@
8787
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
8888
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
8989
// CHECK-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
90-
// CHECK-UBSAN-LINUX-NOT: "-lc"
91-
// CHECK-UBSAN-LINUX: libclang_rt.ubsan-i386.a"
90+
// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
91+
// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
92+
// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
93+
// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
94+
// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
9295
// CHECK-UBSAN-LINUX: "-lpthread"
96+
// CHECK-UBSAN-LINUX-NOT: "-lstdc++"
97+
98+
// RUN: %clangxx -fsanitize=undefined %s -### -o %t.o 2>&1 \
99+
// RUN: -target i386-unknown-linux \
100+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
101+
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-CXX %s
102+
// CHECK-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
103+
// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
104+
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
105+
// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
106+
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
107+
// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
108+
// CHECK-UBSAN-LINUX-CXX: "-lpthread"
109+
// CHECK-UBSAN-LINUX-CXX: "-lstdc++"
110+
111+
// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
112+
// RUN: -target i386-unknown-linux \
113+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
114+
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX %s
115+
// CHECK-ASAN-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
116+
// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.san
117+
// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
118+
// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.san
119+
// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
120+
// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
121+
// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
122+
// CHECK-ASAN-UBSAN-LINUX-NOT: "-lstdc++"
123+
124+
// RUN: %clangxx -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
125+
// RUN: -target i386-unknown-linux \
126+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
127+
// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX-CXX %s
128+
// CHECK-ASAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
129+
// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.san
130+
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
131+
// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.san
132+
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
133+
// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
134+
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
135+
// CHECK-ASAN-UBSAN-LINUX-CXX: "-lstdc++"
93136

94137
// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
95138
// RUN: -target i386-unknown-linux \
96139
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
97140
// RUN: -shared \
98141
// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHARED %s
99142
// CHECK-UBSAN-LINUX-SHARED: "{{.*}}ld{{(.exe)?}}"
100-
// CHECK-UBSAN-LINUX-SHARED-NOT: "-lc"
101-
// CHECK-UBSAN-LINUX-SHARED: libclang_rt.ubsan-i386.a"
102-
// CHECK-UBSAN-LINUX-SHARED: "-lpthread"
143+
// CHECK-UBSAN-LINUX-SHARED-NOT: libclang_rt.ubsan-i386.a"

0 commit comments

Comments
 (0)