Skip to content

Commit c135f6f

Browse files
authored
[TySan] Add initial Type Sanitizer support to Clang) (#76260)
This patch introduces the Clang components of type sanitizer: a sanitizer for type-based aliasing violations. It is based on Hal Finkel's https://reviews.llvm.org/D32198. The Clang changes are mostly formulaic, the one specific change being that when the TBAA sanitizer is enabled, TBAA is always generated, even at -O0. It goes together with the corresponding LLVM changes (#76259) and compiler-rt changes (#76261) PR: #76260
1 parent cf4375d commit c135f6f

File tree

16 files changed

+183
-13
lines changed

16 files changed

+183
-13
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,10 @@ Sanitizers
11761176
<https://clang.llvm.org/docs/SanitizerSpecialCaseList.html>`_. See that link
11771177
for examples.
11781178

1179+
- Introduced an experimental Type Sanitizer, activated by using the
1180+
``-fsanitize=type`` flag. This sanitizer detects violations of C/C++ type-based
1181+
aliasing rules.
1182+
11791183
Python Binding Changes
11801184
----------------------
11811185
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume
102102
FEATURE(memory_sanitizer,
103103
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
104104
SanitizerKind::KernelMemory))
105+
FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
105106
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
106107
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
107108
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))

clang/include/clang/Basic/Sanitizers.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ SANITIZER("fuzzer", Fuzzer)
7373
// libFuzzer-required instrumentation, no linking.
7474
SANITIZER("fuzzer-no-link", FuzzerNoLink)
7575

76+
// TypeSanitizer
77+
SANITIZER("type", Type)
78+
7679
// ThreadSanitizer
7780
SANITIZER("thread", Thread)
7881

clang/include/clang/Driver/SanitizerArgs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class SanitizerArgs {
8787
bool needsHwasanAliasesRt() const {
8888
return needsHwasanRt() && HwasanUseAliases;
8989
}
90+
bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
9091
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
9192
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
9293
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
7878
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
7979
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
80+
#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
8081
#include "llvm/Transforms/ObjCARC.h"
8182
#include "llvm/Transforms/Scalar/EarlyCSE.h"
8283
#include "llvm/Transforms/Scalar/GVN.h"
@@ -735,6 +736,11 @@ static void addSanitizers(const Triple &TargetTriple,
735736
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
736737
}
737738

739+
if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
740+
MPM.addPass(ModuleTypeSanitizerPass());
741+
MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
742+
}
743+
738744
if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
739745
MPM.addPass(NumericalStabilitySanitizerPass());
740746

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
479479
!isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc))
480480
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
481481

482+
if (getLangOpts().Sanitize.has(SanitizerKind::Type) &&
483+
!isInNoSanitizeList(SanitizerKind::Type, Fn, Loc))
484+
Fn->addFnAttr(llvm::Attribute::SanitizeType);
485+
482486
if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
483487
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
484488
Fn->addFnAttr(llvm::Attribute::SanitizeThread);

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
837837
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
838838
if (SanOpts.has(SanitizerKind::Thread))
839839
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
840+
if (SanOpts.has(SanitizerKind::Type))
841+
Fn->addFnAttr(llvm::Attribute::SanitizeType);
840842
if (SanOpts.has(SanitizerKind::NumericalStability))
841843
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
842844
if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
397397
if (LangOpts.HLSL)
398398
createHLSLRuntime();
399399

400-
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
401-
if (LangOpts.Sanitize.has(SanitizerKind::Thread) ||
400+
// Enable TBAA unless it's suppressed. TSan and TySan need TBAA even at O0.
401+
if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Thread | SanitizerKind::Type) ||
402402
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
403403
TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts,
404404
getLangOpts()));

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
314314
}
315315

316316
llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
317-
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
318-
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
317+
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types (unless
318+
// we're running TypeSanitizer).
319+
if (!Features.Sanitize.has(SanitizerKind::Type) &&
320+
(CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing))
319321
return nullptr;
320322

321323
// If the type has the may_alias attribute (even on a typedef), it is

clang/lib/CodeGen/SanitizerMetadata.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ using namespace CodeGen;
1919

2020
SanitizerMetadata::SanitizerMetadata(CodeGenModule &CGM) : CGM(CGM) {}
2121

22-
static bool isAsanHwasanOrMemTag(const SanitizerSet &SS) {
22+
static bool isAsanHwasanMemTagOrTysan(const SanitizerSet &SS) {
2323
return SS.hasOneOf(SanitizerKind::Address | SanitizerKind::KernelAddress |
24-
SanitizerKind::HWAddress | SanitizerKind::MemTag);
24+
SanitizerKind::HWAddress | SanitizerKind::MemTag |
25+
SanitizerKind::Type);
2526
}
2627

2728
static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
@@ -68,7 +69,7 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
6869
SanitizerMask NoSanitizeAttrMask,
6970
bool IsDynInit) {
7071
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
71-
if (!isAsanHwasanOrMemTag(FsanitizeArgument))
72+
if (!isAsanHwasanMemTagOrTysan(FsanitizeArgument))
7273
return;
7374

7475
FsanitizeArgument.Mask = expandKernelSanitizerMasks(FsanitizeArgument.Mask);
@@ -105,11 +106,32 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
105106
GV, Loc, Ty, "init");
106107

107108
GV->setSanitizerMetadata(Meta);
109+
110+
if (Ty.isNull() || !CGM.getLangOpts().Sanitize.has(SanitizerKind::Type) ||
111+
NoSanitizeAttrMask & SanitizerKind::Type)
112+
return;
113+
114+
llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(Ty);
115+
if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
116+
return;
117+
118+
llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
119+
TBAAInfo};
120+
121+
// Metadata for the global already registered.
122+
if (llvm::MDNode::getIfExists(CGM.getLLVMContext(), GlobalMetadata))
123+
return;
124+
125+
llvm::MDNode *ThisGlobal =
126+
llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
127+
llvm::NamedMDNode *TysanGlobals =
128+
CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
129+
TysanGlobals->addOperand(ThisGlobal);
108130
}
109131

110132
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
111133
bool IsDynInit) {
112-
if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
134+
if (!isAsanHwasanMemTagOrTysan(CGM.getLangOpts().Sanitize))
113135
return;
114136
std::string QualName;
115137
llvm::raw_string_ostream OS(QualName);

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
3737
static const SanitizerMask NotAllowedWithExecuteOnly =
3838
SanitizerKind::Function | SanitizerKind::KCFI;
3939
static const SanitizerMask NeedsUnwindTables =
40-
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
41-
SanitizerKind::Memory | SanitizerKind::DataFlow |
40+
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type |
41+
SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow |
4242
SanitizerKind::NumericalStability;
4343
static const SanitizerMask SupportsCoverage =
4444
SanitizerKind::Address | SanitizerKind::HWAddress |
4545
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
46-
SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
47-
SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
48-
SanitizerKind::KernelMemory | SanitizerKind::Leak |
46+
SanitizerKind::Type | SanitizerKind::MemtagStack |
47+
SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals |
48+
SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak |
4949
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
5050
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
5151
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
@@ -182,6 +182,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
182182
{"msan_ignorelist.txt", SanitizerKind::Memory},
183183
{"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
184184
{"tsan_ignorelist.txt", SanitizerKind::Thread},
185+
{"tysan_blacklist.txt", SanitizerKind::Type},
185186
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
186187
{"cfi_ignorelist.txt", SanitizerKind::CFI},
187188
{"ubsan_ignorelist.txt",
@@ -542,6 +543,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
542543
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
543544
std::make_pair(SanitizerKind::Address,
544545
SanitizerKind::Thread | SanitizerKind::Memory),
546+
std::make_pair(SanitizerKind::Type,
547+
SanitizerKind::Address | SanitizerKind::KernelAddress |
548+
SanitizerKind::Memory | SanitizerKind::Leak |
549+
SanitizerKind::Thread | SanitizerKind::KernelAddress),
545550
std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
546551
std::make_pair(SanitizerKind::Leak,
547552
SanitizerKind::Thread | SanitizerKind::Memory),

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14801480
}
14811481
if (SanArgs.needsTsanRt())
14821482
SharedRuntimes.push_back("tsan");
1483+
if (SanArgs.needsTysanRt())
1484+
SharedRuntimes.push_back("tysan");
14831485
if (SanArgs.needsHwasanRt()) {
14841486
if (SanArgs.needsHwasanAliasesRt())
14851487
SharedRuntimes.push_back("hwasan_aliases");
@@ -1552,6 +1554,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
15521554
if (SanArgs.linkCXXRuntimes())
15531555
StaticRuntimes.push_back("tsan_cxx");
15541556
}
1557+
if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
1558+
StaticRuntimes.push_back("tysan");
15551559
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
15561560
if (SanArgs.requiresMinimalRuntime()) {
15571561
StaticRuntimes.push_back("ubsan_minimal");

clang/lib/Driver/ToolChains/Darwin.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
16001600
"Static sanitizer runtimes not supported");
16011601
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
16021602
}
1603+
if (Sanitize.needsTysanRt())
1604+
AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan");
16031605
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
16041606
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
16051607

@@ -3603,6 +3605,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
36033605
Res |= SanitizerKind::Thread;
36043606
}
36053607

3608+
if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
3609+
Res |= SanitizerKind::Type;
3610+
}
3611+
36063612
if (IsX86_64)
36073613
Res |= SanitizerKind::NumericalStability;
36083614

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
837837
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
838838
IsLoongArch64 || IsRISCV64)
839839
Res |= SanitizerKind::Thread;
840+
if (IsX86_64 || IsAArch64)
841+
Res |= SanitizerKind::Type;
840842
if (IsX86_64 || IsSystemZ || IsPowerPC64)
841843
Res |= SanitizerKind::KernelMemory;
842844
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
2+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=TYSAN %s
3+
// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t
4+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s
5+
6+
// The sanitize_type attribute should be attached to functions
7+
// when TypeSanitizer is enabled, unless no_sanitize("type") attribute
8+
// is present.
9+
10+
// WITHOUT: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
11+
// BL: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
12+
// TYSAN: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
13+
__attribute__((no_sanitize("type"))) int NoTYSAN1(int *a) { return *a; }
14+
15+
// WITHOUT: NoTYSAN2{{.*}}) [[NOATTR]]
16+
// BL: NoTYSAN2{{.*}}) [[NOATTR]]
17+
// TYSAN: NoTYSAN2{{.*}}) [[NOATTR]]
18+
__attribute__((no_sanitize("type"))) int NoTYSAN2(int *a);
19+
int NoTYSAN2(int *a) { return *a; }
20+
21+
// WITHOUT: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
22+
// BL: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
23+
// TYSAN: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
24+
__attribute__((no_sanitize("type"))) int NoTYSAN3(int *a) { return *a; }
25+
26+
// WITHOUT: TYSANOk{{.*}}) [[NOATTR]]
27+
// BL: TYSANOk{{.*}}) [[NOATTR]]
28+
// TYSAN: TYSANOk{{.*}}) [[WITH:#[0-9]+]]
29+
int TYSANOk(int *a) { return *a; }
30+
31+
// WITHOUT: TemplateTYSANOk{{.*}}) [[NOATTR]]
32+
// BL: TemplateTYSANOk{{.*}}) [[NOATTR]]
33+
// TYSAN: TemplateTYSANOk{{.*}}) [[WITH]]
34+
template <int i>
35+
int TemplateTYSANOk() { return i; }
36+
37+
// WITHOUT: TemplateNoTYSAN{{.*}}) [[NOATTR]]
38+
// BL: TemplateNoTYSAN{{.*}}) [[NOATTR]]
39+
// TYSAN: TemplateNoTYSAN{{.*}}) [[NOATTR]]
40+
template <int i>
41+
__attribute__((no_sanitize("type"))) int TemplateNoTYSAN() { return i; }
42+
43+
int force_instance = TemplateTYSANOk<42>() + TemplateNoTYSAN<42>();
44+
45+
// Check that __cxx_global_var_init* get the sanitize_type attribute.
46+
int global1 = 0;
47+
int global2 = *(int *)((char *)&global1 + 1);
48+
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
49+
// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
50+
// TYSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]
51+
52+
// Make sure that we don't add globals to the list for which we don't have a
53+
// specific type description.
54+
// FIXME: We now have a type description for this type and a global is added. Should it?
55+
struct SX {
56+
int a, b;
57+
};
58+
SX sx;
59+
60+
void consumer(const char *);
61+
62+
void char_caller() {
63+
// TYSAN: void @_Z11char_callerv()
64+
// TYSAN-NEXT: entry:
65+
// TYSAN-NEXT: call void @_Z8consumerPKc(ptr noundef @.str)
66+
// TYSAN-NEXT: ret void
67+
68+
consumer("foo");
69+
}
70+
71+
// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
72+
73+
// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} }
74+
75+
// TYSAN: attributes [[NOATTR]] = { mustprogress noinline nounwind{{.*}} }
76+
// TYSAN: attributes [[WITH]] = { noinline nounwind sanitize_type{{.*}} }
77+
78+
// TYSAN-DAG: !llvm.tysan.globals = !{[[G1MD:![0-9]+]], [[G2MD:![0-9]+]], [[G3MD:![0-9]+]], [[SXMD:![0-9]+]]}
79+
// TYSAN-DAG: [[G1MD]] = !{ptr @force_instance, [[INTMD:![0-9]+]]}
80+
// TYSAN-DAG: [[INTMD]] = !{!"int",
81+
// TYSAN-DAG: [[G2MD]] = !{ptr @global1, [[INTMD]]}
82+
// TYSAN-DAG: [[G3MD]] = !{ptr @global2, [[INTMD]]}
83+
// TYSAN-DAG: [[SXMD]] = !{ptr @sx, [[SXTYMD:![0-9]+]]}
84+
// TYSAN-DAG: [[SXTYMD]] = !{!"_ZTS2SX", [[INTMD]], i64 0, !1, i64 4}
85+
// TYSAN-DAG: Simple C++ TBAA

clang/test/Driver/sanitizer-ld.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,29 @@
274274
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread"
275275
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lresolv"
276276

277+
278+
// RUN: %clangxx %s -### -o %t.o 2>&1 \
279+
// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
280+
// RUN: -fsanitize=type \
281+
// RUN: -resource-dir=%S/Inputs/resource_dir \
282+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
283+
// RUN: | FileCheck --check-prefix=CHECK-TYSAN-LINUX-CXX %s
284+
//
285+
// CHECK-TYSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
286+
// CHECK-TYSAN-LINUX-CXX-NOT: stdc++
287+
// CHECK-TYSAN-LINUX-CXX: "--whole-archive" "{{.*}}libclang_rt.tysan{{[^.]*}}.a" "--no-whole-archive"
288+
// CHECK-TYSAN-LINUX-CXX: stdc++
289+
290+
// RUN: %clangxx -fsanitize=type -### %s 2>&1 \
291+
// RUN: -mmacosx-version-min=10.6 \
292+
// RUN: --target=x86_64-apple-darwin13.4.0 -fuse-ld=ld -stdlib=platform \
293+
// RUN: -resource-dir=%S/Inputs/resource_dir \
294+
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
295+
// RUN: | FileCheck --check-prefix=CHECK-TYSAN-DARWIN-CXX %s
296+
// CHECK-TYSAN-DARWIN-CXX: "{{.*}}ld{{(.exe)?}}"
297+
// CHECK-TYSAN-DARWIN-CXX: libclang_rt.tysan_osx_dynamic.dylib
298+
// CHECK-TYSAN-DARWIN-CXX-NOT: -lc++abi
299+
277300
// RUN: %clangxx -### %s 2>&1 \
278301
// RUN: --target=x86_64-unknown-linux -fuse-ld=ld -stdlib=platform -lstdc++ \
279302
// RUN: -fsanitize=thread \

0 commit comments

Comments
 (0)