Skip to content

Commit ab8d005

Browse files
committed
[TySan] A Type Sanitizer (Clang)
1 parent a6d44dd commit ab8d005

File tree

16 files changed

+114
-27
lines changed

16 files changed

+114
-27
lines changed

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/CGDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
458458
LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment);
459459
CGM.setStaticLocalDeclAddress(&D, castedAddr);
460460

461-
CGM.getSanitizerMetadata()->reportGlobal(var, D);
461+
CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
462+
CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D);
462463

463464
// Emit global variable debug descriptor for static vars.
464465
CGDebugInfo *DI = getDebugInfo();

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: 7 additions & 5 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()));
@@ -5174,7 +5174,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
51745174
}
51755175

51765176
if (D)
5177-
SanitizerMD->reportGlobal(GV, *D);
5177+
SanitizerMD->reportGlobalToASan(GV, *D);
51785178

51795179
LangAS ExpectedAS =
51805180
D ? D->getType().getAddressSpace()
@@ -5740,7 +5740,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
57405740
if (NeedsGlobalCtor || NeedsGlobalDtor)
57415741
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
57425742

5743-
SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
5743+
SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
5744+
SanitizerMD->reportGlobalToTySan(GV, *D);
57445745

57455746
// Emit global variable debug information.
57465747
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -6630,7 +6631,8 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
66306631
if (Entry)
66316632
*Entry = GV;
66326633

6633-
SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "<string literal>");
6634+
SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
6635+
// FIXME: Should we also report to the TySan?
66346636

66356637
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
66366638
GV->getValueType(), Alignment);

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: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
3131
return Mask;
3232
}
3333

34-
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
35-
SourceLocation Loc, StringRef Name,
36-
QualType Ty,
37-
SanitizerMask NoSanitizeAttrMask,
38-
bool IsDynInit) {
34+
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
35+
SourceLocation Loc, StringRef Name,
36+
QualType Ty,
37+
SanitizerMask NoSanitizeAttrMask,
38+
bool IsDynInit) {
3939
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
4040
if (!isAsanHwasanOrMemTag(FsanitizeArgument))
4141
return;
@@ -72,8 +72,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
7272
GV->setSanitizerMetadata(Meta);
7373
}
7474

75-
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
76-
bool IsDynInit) {
75+
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
76+
const VarDecl &D, bool IsDynInit) {
7777
if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
7878
return;
7979
std::string QualName;
@@ -95,6 +95,30 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
9595
IsDynInit);
9696
}
9797

98+
void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV,
99+
const VarDecl &D) {
100+
if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type))
101+
return;
102+
103+
for (auto Attr : D.specific_attrs<NoSanitizeAttr>())
104+
if (Attr->getMask() & SanitizerKind::Type)
105+
return;
106+
107+
QualType QTy = D.getType();
108+
llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy);
109+
if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
110+
return;
111+
112+
llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
113+
TBAAInfo};
114+
115+
llvm::MDNode *ThisGlobal =
116+
llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
117+
llvm::NamedMDNode *TysanGlobals =
118+
CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
119+
TysanGlobals->addOperand(ThisGlobal);
120+
}
121+
98122
void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
99-
reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
123+
reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
100124
}

clang/lib/CodeGen/SanitizerMetadata.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ class SanitizerMetadata {
3737

3838
public:
3939
SanitizerMetadata(CodeGenModule &CGM);
40-
void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
41-
bool IsDynInit = false);
42-
void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc,
43-
StringRef Name, QualType Ty = {},
44-
SanitizerMask NoSanitizeAttrMask = {},
45-
bool IsDynInit = false);
40+
void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
41+
bool IsDynInit = false);
42+
void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
43+
StringRef Name, QualType Ty = {},
44+
SanitizerMask NoSanitizeAttrMask = {},
45+
bool IsDynInit = false);
46+
void reportGlobalToTySan(llvm::GlobalVariable *GV, const VarDecl &D);
4647
void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
4748
};
4849
} // end namespace CodeGen

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 9 additions & 4 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 |
40+
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread |
4141
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",
@@ -526,6 +527,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
526527
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
527528
std::make_pair(SanitizerKind::Address,
528529
SanitizerKind::Thread | SanitizerKind::Memory),
530+
std::make_pair(SanitizerKind::Type,
531+
SanitizerKind::Address | SanitizerKind::KernelAddress |
532+
SanitizerKind::Memory | SanitizerKind::Leak |
533+
SanitizerKind::Thread | SanitizerKind::KernelAddress),
529534
std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
530535
std::make_pair(SanitizerKind::Leak,
531536
SanitizerKind::Thread | SanitizerKind::Memory),

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1441,8 +1441,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14411441
if (SanArgs.needsScudoRt()) {
14421442
SharedRuntimes.push_back("scudo_standalone");
14431443
}
1444-
if (SanArgs.needsTsanRt())
1444+
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
14451445
SharedRuntimes.push_back("tsan");
1446+
if (SanArgs.needsTysanRt())
1447+
StaticRuntimes.push_back("tysan");
14461448
if (SanArgs.needsHwasanRt()) {
14471449
if (SanArgs.needsHwasanAliasesRt())
14481450
SharedRuntimes.push_back("hwasan_aliases");
@@ -1515,6 +1517,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
15151517
if (SanArgs.linkCXXRuntimes())
15161518
StaticRuntimes.push_back("tsan_cxx");
15171519
}
1520+
if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
1521+
StaticRuntimes.push_back("tysan");
15181522
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
15191523
if (SanArgs.requiresMinimalRuntime()) {
15201524
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
@@ -1596,6 +1596,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
15961596
"Static sanitizer runtimes not supported");
15971597
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
15981598
}
1599+
if (Sanitize.needsTysanRt())
1600+
AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan");
15991601
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
16001602
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
16011603

@@ -3599,6 +3601,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
35993601
Res |= SanitizerKind::Thread;
36003602
}
36013603

3604+
if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
3605+
Res |= SanitizerKind::Type;
3606+
}
3607+
36023608
if (IsX86_64)
36033609
Res |= SanitizerKind::NumericalStability;
36043610

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
819819
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
820820
IsLoongArch64 || IsRISCV64)
821821
Res |= SanitizerKind::Thread;
822+
if (IsX86_64 || IsAArch64)
823+
Res |= SanitizerKind::Type;
822824
if (IsX86_64 || IsSystemZ || IsPowerPC64)
823825
Res |= SanitizerKind::KernelMemory;
824826
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||

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)