Skip to content

Commit f45d4dc

Browse files
committed
[TySan] A Type Sanitizer (Clang)
1 parent b1465a7 commit f45d4dc

File tree

16 files changed

+116
-29
lines changed

16 files changed

+116
-29
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume
100100
FEATURE(memory_sanitizer,
101101
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
102102
SanitizerKind::KernelMemory))
103+
FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
103104
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
104105
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
105106
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
@@ -86,6 +86,7 @@ class SanitizerArgs {
8686
bool needsHwasanAliasesRt() const {
8787
return needsHwasanRt() && HwasanUseAliases;
8888
}
89+
bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
8990
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
9091
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
9192
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
@@ -80,6 +80,7 @@
8080
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
8181
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
8282
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
83+
#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
8384
#include "llvm/Transforms/ObjCARC.h"
8485
#include "llvm/Transforms/Scalar/EarlyCSE.h"
8586
#include "llvm/Transforms/Scalar/GVN.h"
@@ -707,6 +708,11 @@ static void addSanitizers(const Triple &TargetTriple,
707708
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
708709
}
709710

711+
if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
712+
MPM.addPass(ModuleTypeSanitizerPass());
713+
MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
714+
}
715+
710716
auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
711717
if (LangOpts.Sanitize.has(Mask)) {
712718
bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts);

clang/lib/CodeGen/CGDecl.cpp

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

487-
CGM.getSanitizerMetadata()->reportGlobal(var, D);
487+
CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
488+
CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D);
488489

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

clang/lib/CodeGen/CGDeclCXX.cpp

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

476+
if (getLangOpts().Sanitize.has(SanitizerKind::Type) &&
477+
!isInNoSanitizeList(SanitizerKind::Type, Fn, Loc))
478+
Fn->addFnAttr(llvm::Attribute::SanitizeType);
479+
476480
if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
477481
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
478482
Fn->addFnAttr(llvm::Attribute::SanitizeThread);

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
818818
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
819819
if (SanOpts.has(SanitizerKind::Thread))
820820
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
821+
if (SanOpts.has(SanitizerKind::Type))
822+
Fn->addFnAttr(llvm::Attribute::SanitizeType);
821823
if (SanOpts.has(SanitizerKind::NumericalStability))
822824
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
823825
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
@@ -399,8 +399,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
399399
if (LangOpts.HLSL)
400400
createHLSLRuntime();
401401

402-
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
403-
if (LangOpts.Sanitize.has(SanitizerKind::Thread) ||
402+
// Enable TBAA unless it's suppressed. TSan and TySan need TBAA even at O0.
403+
if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Thread | SanitizerKind::Type) ||
404404
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
405405
TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts,
406406
getLangOpts(), getCXXABI().getMangleContext()));
@@ -5041,7 +5041,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
50415041
}
50425042

50435043
if (D)
5044-
SanitizerMD->reportGlobal(GV, *D);
5044+
SanitizerMD->reportGlobalToASan(GV, *D);
50455045

50465046
LangAS ExpectedAS =
50475047
D ? D->getType().getAddressSpace()
@@ -5594,7 +5594,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
55945594
if (NeedsGlobalCtor || NeedsGlobalDtor)
55955595
EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor);
55965596

5597-
SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
5597+
SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
5598+
SanitizerMD->reportGlobalToTySan(GV, *D);
55985599

55995600
// Emit global variable debug information.
56005601
if (CGDebugInfo *DI = getModuleDebugInfo())
@@ -6471,7 +6472,8 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
64716472
if (Entry)
64726473
*Entry = GV;
64736474

6474-
SanitizerMD->reportGlobal(GV, S->getStrTokenLoc(0), "<string literal>");
6475+
SanitizerMD->reportGlobalToASan(GV, S->getStrTokenLoc(0), "<string literal>");
6476+
// FIXME: Should we also report to the TySan?
64756477

64766478
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
64776479
GV->getValueType(), Alignment);

clang/lib/CodeGen/CodeGenTBAA.cpp

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

229229
llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
230-
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
231-
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
230+
// At -O0 or relaxed aliasing, TBAA is not emitted for regular types (unless
231+
// we're running TypeSanitizer).
232+
if (!Features.Sanitize.has(SanitizerKind::Type) &&
233+
(CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing))
232234
return nullptr;
233235

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

clang/lib/CodeGen/SanitizerMetadata.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
3434
return Mask;
3535
}
3636

37-
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
38-
SourceLocation Loc, StringRef Name,
39-
QualType Ty,
40-
SanitizerMask NoSanitizeAttrMask,
41-
bool IsDynInit) {
37+
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
38+
SourceLocation Loc, StringRef Name,
39+
QualType Ty,
40+
SanitizerMask NoSanitizeAttrMask,
41+
bool IsDynInit) {
4242
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
4343
if (!isAsanHwasanOrMemTag(FsanitizeArgument))
4444
return;
@@ -75,8 +75,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
7575
GV->setSanitizerMetadata(Meta);
7676
}
7777

78-
void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
79-
bool IsDynInit) {
78+
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
79+
const VarDecl &D, bool IsDynInit) {
8080
if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
8181
return;
8282
std::string QualName;
@@ -94,10 +94,34 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
9494
return NoSanitizeMask;
9595
};
9696

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

101125
void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
102-
reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
126+
reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
103127
}

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
@@ -40,15 +40,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
4040
static const SanitizerMask NotAllowedWithExecuteOnly =
4141
SanitizerKind::Function | SanitizerKind::KCFI;
4242
static const SanitizerMask NeedsUnwindTables =
43-
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
43+
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread |
4444
SanitizerKind::Memory | SanitizerKind::DataFlow |
4545
SanitizerKind::NumericalStability;
4646
static const SanitizerMask SupportsCoverage =
4747
SanitizerKind::Address | SanitizerKind::HWAddress |
4848
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
49-
SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
50-
SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
51-
SanitizerKind::KernelMemory | SanitizerKind::Leak |
49+
SanitizerKind::Type | SanitizerKind::MemtagStack |
50+
SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals |
51+
SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak |
5252
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
5353
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
5454
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
@@ -179,6 +179,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
179179
{"msan_ignorelist.txt", SanitizerKind::Memory},
180180
{"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
181181
{"tsan_ignorelist.txt", SanitizerKind::Thread},
182+
{"tysan_blacklist.txt", SanitizerKind::Type},
182183
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
183184
{"cfi_ignorelist.txt", SanitizerKind::CFI},
184185
{"ubsan_ignorelist.txt",
@@ -523,6 +524,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
523524
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
524525
std::make_pair(SanitizerKind::Address,
525526
SanitizerKind::Thread | SanitizerKind::Memory),
527+
std::make_pair(SanitizerKind::Type,
528+
SanitizerKind::Address | SanitizerKind::KernelAddress |
529+
SanitizerKind::Memory | SanitizerKind::Leak |
530+
SanitizerKind::Thread | SanitizerKind::KernelAddress),
526531
std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
527532
std::make_pair(SanitizerKind::Leak,
528533
SanitizerKind::Thread | SanitizerKind::Memory),

clang/lib/Driver/ToolChains/CommonArgs.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,8 +1408,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14081408
if (SanArgs.needsScudoRt()) {
14091409
SharedRuntimes.push_back("scudo_standalone");
14101410
}
1411-
if (SanArgs.needsTsanRt())
1411+
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
14121412
SharedRuntimes.push_back("tsan");
1413+
if (SanArgs.needsTysanRt())
1414+
StaticRuntimes.push_back("tysan");
14131415
if (SanArgs.needsHwasanRt()) {
14141416
if (SanArgs.needsHwasanAliasesRt())
14151417
SharedRuntimes.push_back("hwasan_aliases");
@@ -1474,6 +1476,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
14741476
if (SanArgs.linkCXXRuntimes())
14751477
StaticRuntimes.push_back("tsan_cxx");
14761478
}
1479+
if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
1480+
StaticRuntimes.push_back("tysan");
14771481
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
14781482
if (SanArgs.requiresMinimalRuntime()) {
14791483
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
@@ -1532,6 +1532,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
15321532
"Static sanitizer runtimes not supported");
15331533
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
15341534
}
1535+
if (Sanitize.needsTysanRt())
1536+
AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan");
15351537
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
15361538
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);
15371539

@@ -3474,6 +3476,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
34743476
Res |= SanitizerKind::Thread;
34753477
}
34763478

3479+
if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
3480+
Res |= SanitizerKind::Type;
3481+
}
3482+
34773483
if (IsX86_64)
34783484
Res |= SanitizerKind::NumericalStability;
34793485

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
815815
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
816816
IsLoongArch64 || IsRISCV64)
817817
Res |= SanitizerKind::Thread;
818+
if (IsX86_64 || IsAArch64)
819+
Res |= SanitizerKind::Type;
818820
if (IsX86_64 || IsSystemZ || IsPowerPC64)
819821
Res |= SanitizerKind::KernelMemory;
820822
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
@@ -267,6 +267,29 @@
267267
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread"
268268
// CHECK-ASAN-ANDROID-SHARED-NOT: "-lresolv"
269269

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

0 commit comments

Comments
 (0)