Skip to content

[TySan] Fixed false positive when accessing offset member variables #95387

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ FEATURE(numerical_stability_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Nume
FEATURE(memory_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory |
SanitizerKind::KernelMemory))
FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ SANITIZER("fuzzer", Fuzzer)
// libFuzzer-required instrumentation, no linking.
SANITIZER("fuzzer-no-link", FuzzerNoLink)

// TypeSanitizer
SANITIZER("type", Type)

// ThreadSanitizer
SANITIZER("thread", Thread)

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class SanitizerArgs {
bool needsHwasanAliasesRt() const {
return needsHwasanRt() && HwasanUseAliases;
}
bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/Instrumentation/TypeSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/GVN.h"
Expand Down Expand Up @@ -735,6 +736,11 @@ static void addSanitizers(const Triple &TargetTriple,
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}

if (LangOpts.Sanitize.has(SanitizerKind::Type)) {
MPM.addPass(ModuleTypeSanitizerPass());
MPM.addPass(createModuleToFunctionPassAdaptor(TypeSanitizerPass()));
}

if (LangOpts.Sanitize.has(SanitizerKind::NumericalStability))
MPM.addPass(NumericalStabilitySanitizerPass());

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
LocalDeclMap.find(&D)->second = Address(castedAddr, elemTy, alignment);
CGM.setStaticLocalDeclAddress(&D, castedAddr);

CGM.getSanitizerMetadata()->reportGlobal(var, D);
CGM.getSanitizerMetadata()->reportGlobalToASan(var, D);
CGM.getSanitizerMetadata()->reportGlobalToTySan(var, D);

// Emit global variable debug descriptor for static vars.
CGDebugInfo *DI = getDebugInfo();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,10 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
!isInNoSanitizeList(SanitizerKind::MemtagStack, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);

if (getLangOpts().Sanitize.has(SanitizerKind::Type) &&
!isInNoSanitizeList(SanitizerKind::Type, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeType);

if (getLangOpts().Sanitize.has(SanitizerKind::Thread) &&
!isInNoSanitizeList(SanitizerKind::Thread, Fn, Loc))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
Fn->addFnAttr(llvm::Attribute::SanitizeMemTag);
if (SanOpts.has(SanitizerKind::Thread))
Fn->addFnAttr(llvm::Attribute::SanitizeThread);
if (SanOpts.has(SanitizerKind::Type))
Fn->addFnAttr(llvm::Attribute::SanitizeType);
if (SanOpts.has(SanitizerKind::NumericalStability))
Fn->addFnAttr(llvm::Attribute::SanitizeNumericalStability);
if (SanOpts.hasOneOf(SanitizerKind::Memory | SanitizerKind::KernelMemory))
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
if (LangOpts.HLSL)
createHLSLRuntime();

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

if (D)
SanitizerMD->reportGlobal(GV, *D);
SanitizerMD->reportGlobalToASan(GV, *D);

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

SanitizerMD->reportGlobal(GV, *D, NeedsGlobalCtor);
SanitizerMD->reportGlobalToASan(GV, *D, NeedsGlobalCtor);
SanitizerMD->reportGlobalToTySan(GV, *D);

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

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

return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
GV->getValueType(), Alignment);
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CodeGenTBAA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
}

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

// If the type has the may_alias attribute (even on a typedef), it is
Expand Down
42 changes: 33 additions & 9 deletions clang/lib/CodeGen/SanitizerMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ static SanitizerMask expandKernelSanitizerMasks(SanitizerMask Mask) {
return Mask;
}

void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
SourceLocation Loc, StringRef Name,
QualType Ty,
SanitizerMask NoSanitizeAttrMask,
bool IsDynInit) {
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
SourceLocation Loc, StringRef Name,
QualType Ty,
SanitizerMask NoSanitizeAttrMask,
bool IsDynInit) {
SanitizerSet FsanitizeArgument = CGM.getLangOpts().Sanitize;
if (!isAsanHwasanOrMemTag(FsanitizeArgument))
return;
Expand Down Expand Up @@ -72,8 +72,8 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
GV->setSanitizerMetadata(Meta);
}

void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
bool IsDynInit) {
void SanitizerMetadata::reportGlobalToASan(llvm::GlobalVariable *GV,
const VarDecl &D, bool IsDynInit) {
if (!isAsanHwasanOrMemTag(CGM.getLangOpts().Sanitize))
return;
std::string QualName;
Expand All @@ -91,10 +91,34 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
return NoSanitizeMask;
};

reportGlobal(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
reportGlobalToASan(GV, D.getLocation(), QualName, D.getType(), getNoSanitizeMask(D),
IsDynInit);
}

void SanitizerMetadata::reportGlobalToTySan(llvm::GlobalVariable *GV,
const VarDecl &D) {
if (!CGM.getLangOpts().Sanitize.has(SanitizerKind::Type))
return;

for (auto Attr : D.specific_attrs<NoSanitizeAttr>())
if (Attr->getMask() & SanitizerKind::Type)
return;

QualType QTy = D.getType();
llvm::MDNode *TBAAInfo = CGM.getTBAATypeInfo(QTy);
if (!TBAAInfo || TBAAInfo == CGM.getTBAATypeInfo(CGM.getContext().CharTy))
return;

llvm::Metadata *GlobalMetadata[] = {llvm::ConstantAsMetadata::get(GV),
TBAAInfo};

llvm::MDNode *ThisGlobal =
llvm::MDNode::get(CGM.getLLVMContext(), GlobalMetadata);
llvm::NamedMDNode *TysanGlobals =
CGM.getModule().getOrInsertNamedMetadata("llvm.tysan.globals");
TysanGlobals->addOperand(ThisGlobal);
}

void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
reportGlobal(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
reportGlobalToASan(GV, SourceLocation(), "", QualType(), SanitizerKind::All);
}
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/SanitizerMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ class SanitizerMetadata {

public:
SanitizerMetadata(CodeGenModule &CGM);
void reportGlobal(llvm::GlobalVariable *GV, const VarDecl &D,
bool IsDynInit = false);
void reportGlobal(llvm::GlobalVariable *GV, SourceLocation Loc,
StringRef Name, QualType Ty = {},
SanitizerMask NoSanitizeAttrMask = {},
bool IsDynInit = false);
void reportGlobalToASan(llvm::GlobalVariable *GV, const VarDecl &D,
bool IsDynInit = false);
void reportGlobalToASan(llvm::GlobalVariable *GV, SourceLocation Loc,
StringRef Name, QualType Ty = {},
SanitizerMask NoSanitizeAttrMask = {},
bool IsDynInit = false);
void reportGlobalToTySan(llvm::GlobalVariable *GV, const VarDecl &D);
void disableSanitizerForGlobal(llvm::GlobalVariable *GV);
};
} // end namespace CodeGen
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithExecuteOnly =
SanitizerKind::Function | SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow |
SanitizerKind::NumericalStability;
static const SanitizerMask SupportsCoverage =
SanitizerKind::Address | SanitizerKind::HWAddress |
SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress |
SanitizerKind::MemtagStack | SanitizerKind::MemtagHeap |
SanitizerKind::MemtagGlobals | SanitizerKind::Memory |
SanitizerKind::KernelMemory | SanitizerKind::Leak |
SanitizerKind::Type | SanitizerKind::MemtagStack |
SanitizerKind::MemtagHeap | SanitizerKind::MemtagGlobals |
SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak |
SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
Expand Down Expand Up @@ -182,6 +182,7 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds,
{"msan_ignorelist.txt", SanitizerKind::Memory},
{"nsan_ignorelist.txt", SanitizerKind::NumericalStability},
{"tsan_ignorelist.txt", SanitizerKind::Thread},
{"tysan_blacklist.txt", SanitizerKind::Type},
{"dfsan_abilist.txt", SanitizerKind::DataFlow},
{"cfi_ignorelist.txt", SanitizerKind::CFI},
{"ubsan_ignorelist.txt",
Expand Down Expand Up @@ -526,6 +527,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
std::pair<SanitizerMask, SanitizerMask> IncompatibleGroups[] = {
std::make_pair(SanitizerKind::Address,
SanitizerKind::Thread | SanitizerKind::Memory),
std::make_pair(SanitizerKind::Type,
SanitizerKind::Address | SanitizerKind::KernelAddress |
SanitizerKind::Memory | SanitizerKind::Leak |
SanitizerKind::Thread | SanitizerKind::KernelAddress),
std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
std::make_pair(SanitizerKind::Leak,
SanitizerKind::Thread | SanitizerKind::Memory),
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1441,8 +1441,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.needsScudoRt()) {
SharedRuntimes.push_back("scudo_standalone");
}
if (SanArgs.needsTsanRt())
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("tsan");
if (SanArgs.needsTysanRt())
StaticRuntimes.push_back("tysan");
if (SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
Expand Down Expand Up @@ -1515,6 +1517,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
StaticRuntimes.push_back("tysan");
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("ubsan_minimal");
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
"Static sanitizer runtimes not supported");
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
}
if (Sanitize.needsTysanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "tysan");
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false);

Expand Down Expand Up @@ -3599,6 +3601,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Thread;
}

if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
Res |= SanitizerKind::Type;
}

if (IsX86_64)
Res |= SanitizerKind::NumericalStability;

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
IsLoongArch64 || IsRISCV64)
Res |= SanitizerKind::Thread;
if (IsX86_64 || IsAArch64)
Res |= SanitizerKind::Type;
if (IsX86_64 || IsSystemZ || IsPowerPC64)
Res |= SanitizerKind::KernelMemory;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
Expand Down
2 changes: 1 addition & 1 deletion clang/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
COMPONENT compiler-rt)

# Add top-level targets that build specific compiler-rt runtimes.
set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal)
set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan tysan ubsan ubsan-minimal)
foreach(runtime ${COMPILER_RT_RUNTIMES})
get_ext_project_build_command(build_runtime_cmd ${runtime})
add_custom_target(${runtime}
Expand Down
74 changes: 74 additions & 0 deletions clang/test/CodeGen/sanitize-type-attr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type | FileCheck -check-prefix=TYSAN %s
// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -fsanitize=type -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s

// The sanitize_type attribute should be attached to functions
// when TypeSanitizer is enabled, unless no_sanitize("type") attribute
// is present.

// WITHOUT: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
// BL: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
// TYSAN: NoTYSAN1{{.*}}) [[NOATTR:#[0-9]+]]
__attribute__((no_sanitize("type"))) int NoTYSAN1(int *a) { return *a; }

// WITHOUT: NoTYSAN2{{.*}}) [[NOATTR]]
// BL: NoTYSAN2{{.*}}) [[NOATTR]]
// TYSAN: NoTYSAN2{{.*}}) [[NOATTR]]
__attribute__((no_sanitize("type"))) int NoTYSAN2(int *a);
int NoTYSAN2(int *a) { return *a; }

// WITHOUT: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
// BL: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
// TYSAN: NoTYSAN3{{.*}}) [[NOATTR:#[0-9]+]]
__attribute__((no_sanitize("type"))) int NoTYSAN3(int *a) { return *a; }

// WITHOUT: TYSANOk{{.*}}) [[NOATTR]]
// BL: TYSANOk{{.*}}) [[NOATTR]]
// TYSAN: TYSANOk{{.*}}) [[WITH:#[0-9]+]]
int TYSANOk(int *a) { return *a; }

// WITHOUT: TemplateTYSANOk{{.*}}) [[NOATTR]]
// BL: TemplateTYSANOk{{.*}}) [[NOATTR]]
// TYSAN: TemplateTYSANOk{{.*}}) [[WITH]]
template <int i>
int TemplateTYSANOk() { return i; }

// WITHOUT: TemplateNoTYSAN{{.*}}) [[NOATTR]]
// BL: TemplateNoTYSAN{{.*}}) [[NOATTR]]
// TYSAN: TemplateNoTYSAN{{.*}}) [[NOATTR]]
template <int i>
__attribute__((no_sanitize("type"))) int TemplateNoTYSAN() { return i; }

int force_instance = TemplateTYSANOk<42>() + TemplateNoTYSAN<42>();

// Check that __cxx_global_var_init* get the sanitize_type attribute.
int global1 = 0;
int global2 = *(int *)((char *)&global1 + 1);
// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
// BL: @__cxx_global_var_init{{.*}}[[NOATTR:#[0-9]+]]
// TYSAN: @__cxx_global_var_init{{.*}}[[WITH:#[0-9]+]]

// Make sure that we don't add globals to the list for which we don't have a
// specific type description.
// FIXME: We now have a type description for this type and a global is added. Should it?
struct SX {
int a, b;
};
SX sx;

// WITHOUT: attributes [[NOATTR]] = { noinline nounwind{{.*}} }

// BL: attributes [[NOATTR]] = { noinline nounwind{{.*}} }

// TYSAN: attributes [[NOATTR]] = { mustprogress noinline nounwind{{.*}} }
// TYSAN: attributes [[WITH]] = { noinline nounwind sanitize_type{{.*}} }

// TYSAN-DAG: !llvm.tysan.globals = !{[[G1MD:![0-9]+]], [[G2MD:![0-9]+]], [[G3MD:![0-9]+]], [[SXMD:![0-9]+]]}
// TYSAN-DAG: [[G1MD]] = !{ptr @force_instance, [[INTMD:![0-9]+]]}
// TYSAN-DAG: [[INTMD]] = !{!"int",
// TYSAN-DAG: [[G2MD]] = !{ptr @global1, [[INTMD]]}
// TYSAN-DAG: [[G3MD]] = !{ptr @global2, [[INTMD]]}
// TYSAN-DAG: [[SXMD]] = !{ptr @sx, [[SXTYMD:![0-9]+]]}
// TYSAN-DAG: [[SXTYMD]] = !{!"_ZTS2SX", [[INTMD]], i64 0, !1, i64 4}
// TYSAN-DAG: Simple C++ TBAA
Loading
Loading