Skip to content

[Sanitizer] Make sanitizer passes idempotent #99439

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

Merged
merged 1 commit into from
Aug 12, 2024
Merged
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
2 changes: 1 addition & 1 deletion clang/test/CodeGenObjC/no-sanitize.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

@interface I0 @end
@implementation I0
// CHECK-NOT: sanitize_address
// CHECK-NOT: Function Attrs: sanitize_address
- (void) im0: (int) a0 __attribute__((no_sanitize("address"))) {
int (^blockName)(void) = ^int(void) { return 0; };
}
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Transforms/Instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class Triple;
class OptimizationRemarkEmitter;
class Comdat;
class CallBase;
class Module;

/// Check if module has flag attached, if not add the flag.
bool checkIfAlreadyInstrumented(Module &M, StringRef Flag);

/// Instrumentation passes often insert conditional checks into entry blocks.
/// Call this function before splitting the entry block to move instructions
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,11 @@ AddressSanitizerPass::AddressSanitizerPass(

PreservedAnalyses AddressSanitizerPass::run(Module &M,
ModuleAnalysisManager &MAM) {
// Return early if nosanitize_address module flag is present for the module.
// This implies that asan pass has already run before.
if (checkIfAlreadyInstrumented(M, "nosanitize_address"))
return PreservedAnalyses::all();

ModuleAddressSanitizer ModuleSanitizer(
M, Options.InsertVersionCheck, Options.CompileKernel, Options.Recover,
UseGlobalGC, UseOdrIndicator, DestructorKind, ConstructorKind);
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3473,6 +3473,9 @@ void DFSanVisitor::visitPHINode(PHINode &PN) {

PreservedAnalyses DataFlowSanitizerPass::run(Module &M,
ModuleAnalysisManager &AM) {
// Return early if nosanitize_dataflow module flag is present for the module.
if (checkIfAlreadyInstrumented(M, "nosanitize_dataflow"))
return PreservedAnalyses::all();
auto GetTLI = [&](Function &F) -> TargetLibraryInfo & {
auto &FAM =
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
Expand Down Expand Up @@ -455,6 +456,9 @@ class HWAddressSanitizer {

PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
ModuleAnalysisManager &MAM) {
// Return early if nosanitize_hwaddress module flag is present for the module.
if (checkIfAlreadyInstrumented(M, "nosanitize_hwaddress"))
return PreservedAnalyses::all();
const StackSafetyGlobalInfo *SSI = nullptr;
auto TargetTriple = llvm::Triple(M.getTargetTriple());
if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))
Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/Transforms/Instrumentation/Instrumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,47 @@
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Instrumentation.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/TargetParser/Triple.h"

using namespace llvm;

static cl::opt<bool> ClIgnoreRedundantInstrumentation(
"ignore-redundant-instrumentation",
cl::desc("Ignore redundant instrumentation"), cl::Hidden, cl::init(false));

namespace {
/// Diagnostic information for IR instrumentation reporting.
class DiagnosticInfoInstrumentation : public DiagnosticInfo {
const Twine &Msg;

public:
DiagnosticInfoInstrumentation(const Twine &DiagMsg,
DiagnosticSeverity Severity = DS_Warning)
: DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
void print(DiagnosticPrinter &DP) const override { DP << Msg; }
};
} // namespace

/// Check if module has flag attached, if not add the flag.
bool llvm::checkIfAlreadyInstrumented(Module &M, StringRef Flag) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early return please and DS_Error?

Suggested change
bool llvm::checkIfAlreadyInstrumented(Module &M, StringRef Flag) {
bool llvm::checkIfAlreadyInstrumented(Module &M, StringRef Flag) {
if (!M.getModuleFlag(Flag)) {
M.addModuleFlag(Module::ModFlagBehavior::Override, Flag, 1);
return false;
}
if (ClIgnoreRedundantInstrumentation)
return true;
std::string diagInfo =
"Redundant instrumentation detected, with module flag: " +
std::string(Flag);
M.getContext().diagnose(DiagnosticInfoInstrumentation(
diagInfo, DiagnosticSeverity::DS_Error));
return true;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. Have updated the patch in the latest commit.
Using DS_Error, causes second run of the pass to abort with error. So retained DS_Warning, so this returns true without abort and sanitizer passes return without doing second instrumentation.

if (!M.getModuleFlag(Flag)) {
M.addModuleFlag(Module::ModFlagBehavior::Override, Flag, 1);
return false;
}
if (ClIgnoreRedundantInstrumentation)
return true;
std::string diagInfo =
"Redundant instrumentation detected, with module flag: " +
std::string(Flag);
M.getContext().diagnose(
DiagnosticInfoInstrumentation(diagInfo, DiagnosticSeverity::DS_Warning));
return true;
}

/// Moves I before IP. Returns new insert point.
static BasicBlock::iterator moveBeforeInsertPoint(BasicBlock::iterator I, BasicBlock::iterator IP) {
// If I is IP, move the insert point down.
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
Expand Down Expand Up @@ -706,6 +707,9 @@ MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K,

PreservedAnalyses MemorySanitizerPass::run(Module &M,
ModuleAnalysisManager &AM) {
// Return early if nosanitize_memory module flag is present for the module.
if (checkIfAlreadyInstrumented(M, "nosanitize_memory"))
return PreservedAnalyses::all();
bool Modified = false;
if (!Options.Kernel) {
insertModuleCtor(M);
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ PreservedAnalyses ThreadSanitizerPass::run(Function &F,

PreservedAnalyses ModuleThreadSanitizerPass::run(Module &M,
ModuleAnalysisManager &MAM) {
// Return early if nosanitize_thread module flag is present for the module.
if (checkIfAlreadyInstrumented(M, "nosanitize_thread"))
return PreservedAnalyses::all();
insertModuleCtor(M);
return PreservedAnalyses::none();
}
Expand Down
55 changes: 55 additions & 0 deletions llvm/test/Instrumentation/AddressSanitizer/asan-pass-second-run.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
; This test checks in the second run, function is not instrumented again.
; RUN: opt < %s -passes=asan,asan -S | FileCheck %s
Copy link
Collaborator

@vitalybuka vitalybuka Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed (the patch)?

Time to time we had discussion to do exactly like that, but usually it's not hard to make sure that pass is unique in pipeline

There is also ConstructorKind::kNone when constructor is not inserted.

Inconsistency with other sanitizers is also not nice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We found this issue when a HIP program is first compiled to bitcode with -fsanitize=address, then the bitcode is compiled to object file with -fsanitize=address again. This lead to calculation of shadow memory twice due to double instrumentation.

As you pointed out, ConstructorKind::None can lead to asan.module_ctor to be not present in the module. Do you suggest any other way to check if module is instrumented?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitalybuka I think it's a good idea to make all sanitizers idempotent. Your guidance on preferred approaches would be appreciated. With separate compilation, runtime compilation, etc. it seems hard to always "make sure that pass is unique in the pipeline".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have some generic approach, which will work regardless of constructors.

How about about Module::addModuleFlag("nosanitize") which will be set and checked by every sanitizer?

I am not sure if this require RFC on discourse. @nikic @efriedma-quic WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have updated PR to use "nosanitize" module flag. Could also check the return value for key "nosanitize". Currently its set to "1" at end of asan pass run.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure a generic nosanitize module flag makes sense. Things will break if there are two sanitizers that aren't mutually exclusive and both try to use the flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikic Could something like below be done so that sanitizers don't confuse with just "nosanitize" flag?

Add module flag "nosanitize" with a key that is enum SanitizerKind (with all supported sanitizers listed in it), defined in common header file for sanitizers. So, before running the pass, query the "nosanitize" flag and check that corresponding key value is present, to check if the pass has previously instrumented the IR.

M.addModuleFlag(Module::ModFlagBehavior::Override, "nosanitize", SanitizerKind::Address);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd want a separate module flag for each sanitizer.

I'm a little skeptical that you pass pipeline is really doing what you want if you end up running sanitizer passes twice; that indicates you're running a bunch of other optimization passes twice without a good reason.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instrumenting a shadow load practically guarantees an immediate memory fault or other catastrophic behavior. I assume any optimization passes that could cause such trouble are already idempotent.

Copy link
Collaborator

@vitalybuka vitalybuka Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nikic We don't have such mixing-compartible instrumenting sanitizers yet, but having unique flags is LGTM

@efriedma-quic all previous proposals to add such "re-run" protection ended up with "the pipeline is wrong". But implementation is so trivial, so I don't mind just to have it implemented.


target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function with sanitize_address is instrumented.
; Function Attrs: nounwind uwtable
;.
; CHECK: @___asan_globals_registered = common hidden global i64 0
; CHECK: @__start_asan_globals = extern_weak hidden global i64
; CHECK: @__stop_asan_globals = extern_weak hidden global i64
;.
define void @instr_sa(ptr %a) sanitize_address {
; CHECK: Function Attrs: sanitize_address
; CHECK-LABEL: define void @instr_sa(
; CHECK-SAME: ptr [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[TMP0]], 3
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 2147450880
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1
; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i8 [[TMP4]], 0
; CHECK-NEXT: br i1 [[TMP5]], label %[[BB6:.*]], label %[[BB12:.*]], !prof [[PROF1:![0-9]+]]
; CHECK: [[BB6]]:
; CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP0]], 7
; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], 3
; CHECK-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP8]] to i8
; CHECK-NEXT: [[TMP10:%.*]] = icmp sge i8 [[TMP9]], [[TMP4]]
; CHECK-NEXT: br i1 [[TMP10]], label %[[BB11:.*]], label %[[BB12]]
; CHECK: [[BB11]]:
; CHECK-NEXT: call void @__asan_report_load4(i64 [[TMP0]]) #[[ATTR2:[0-9]+]]
; CHECK-NEXT: unreachable
; CHECK: [[BB12]]:
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
; CHECK-NEXT: store i32 [[TMP2]], ptr [[A]], align 4
; CHECK-NEXT: ret void
;
entry:
%tmp1 = load i32, ptr %a, align 4
%tmp2 = add i32 %tmp1, 1
store i32 %tmp2, ptr %a, align 4
ret void
}
;.
; CHECK: attributes #[[ATTR0]] = { sanitize_address }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
; CHECK: attributes #[[ATTR2]] = { nomerge }
;.
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_address", i32 1}
; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
;.
2 changes: 1 addition & 1 deletion llvm/test/Instrumentation/AddressSanitizer/missing_dbg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ entry:
!4 = !DISubroutineType(types: !5)
!5 = !{}

; CHECK: [[DBG]] = !DILocation(line: 0, scope: !3)
; CHECK: [[DBG]] = !DILocation(line: 0, scope: !4)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: opt < %s -passes=dfsan,dfsan -S | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define i8 @add(i8 %a, i8 %b) {
; CHECK: @add.dfsan
; CHECK-DAG: %[[#ALABEL:]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
; CHECK-DAG: %[[#BLABEL:]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
; CHECK: %[[#UNION:]] = or i8 %[[#ALABEL]], %[[#BLABEL]]
; CHECK: %c = add i8 %a, %b
; CHECK: store i8 %[[#UNION]], ptr @__dfsan_retval_tls, align [[ALIGN]]
; CHECK: ret i8 %c
%c = add i8 %a, %b
ret i8 %c
}

; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_dataflow", i32 1}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
; Test basic address sanitizer instrumentation.
;
; RUN: opt < %s -passes=hwasan,hwasan -S | FileCheck %s

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

;.
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @hwasan.module_ctor], section "llvm.metadata"
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @hwasan.module_ctor, ptr @hwasan.module_ctor }]
; CHECK: @__start_hwasan_globals = external hidden constant [0 x i8]
; CHECK: @__stop_hwasan_globals = external hidden constant [0 x i8]
; CHECK: @hwasan.note = private constant { i32, i32, i32, [8 x i8], i32, i32 } { i32 8, i32 8, i32 3, [8 x i8] c"LLVM\00\00\00\00", i32 trunc (i64 sub (i64 ptrtoint (ptr @__start_hwasan_globals to i64), i64 ptrtoint (ptr @hwasan.note to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @__stop_hwasan_globals to i64), i64 ptrtoint (ptr @hwasan.note to i64)) to i32) }, section ".note.hwasan.globals", comdat($hwasan.module_ctor), align 4
; CHECK: @hwasan.dummy.global = private constant [0 x i8] zeroinitializer, section "hwasan_globals", comdat($hwasan.module_ctor), !associated [[META0:![0-9]+]]
; CHECK: @__hwasan_tls = external thread_local(initialexec) global i64
; CHECK: @llvm.compiler.used = appending global [3 x ptr] [ptr @hwasan.note, ptr @hwasan.dummy.global, ptr @__hwasan_tls], section "llvm.metadata"
; CHECK: @__hwasan_shadow = external global [0 x i8]
;.
define i8 @test_load8(ptr %a) sanitize_hwaddress {
; CHECK: Function Attrs: sanitize_hwaddress
; CHECK-LABEL: define i8 @test_load8
; CHECK-SAME: (ptr [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr null)
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
; CHECK-NEXT: call void @__hwasan_load1(i64 [[TMP0]])
; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[A]], align 4
; CHECK-NEXT: ret i8 [[B]]
;
entry:
%b = load i8, ptr %a, align 4
ret i8 %b
}
;.
; CHECK: attributes #[[ATTR0]] = { sanitize_hwaddress }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
;.
; CHECK: [[META0]] = !{ptr @hwasan.note}
; CHECK: [[META1:![0-9]+]] = !{i32 4, !"nosanitize_hwaddress", i32 1}
;.
43 changes: 43 additions & 0 deletions llvm/test/Instrumentation/MemorySanitizer/msan-pass-second-run.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
; This test checks in the second run, function is not instrumented again.
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan,msan | FileCheck %s

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

;.
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @msan.module_ctor], section "llvm.metadata"
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @msan.module_ctor, ptr null }]
; CHECK: @__msan_retval_tls = external thread_local(initialexec) global [100 x i64]
; CHECK: @__msan_retval_origin_tls = external thread_local(initialexec) global i32
; CHECK: @__msan_param_tls = external thread_local(initialexec) global [100 x i64]
; CHECK: @__msan_param_origin_tls = external thread_local(initialexec) global [200 x i32]
; CHECK: @__msan_va_arg_tls = external thread_local(initialexec) global [100 x i64]
; CHECK: @__msan_va_arg_origin_tls = external thread_local(initialexec) global [200 x i32]
; CHECK: @__msan_va_arg_overflow_size_tls = external thread_local(initialexec) global i64
;.
define void @array() sanitize_memory {
; CHECK: Function Attrs: sanitize_memory
; CHECK-LABEL: define void @array(
; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: call void @llvm.donothing()
; CHECK-NEXT: [[X:%.*]] = alloca i32, i64 5, align 4
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = xor i64 [[TMP0]], 87960930222080
; CHECK-NEXT: [[TMP2:%.*]] = inttoptr i64 [[TMP1]] to ptr
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP2]], i8 -1, i64 20, i1 false)
; CHECK-NEXT: ret void
;
entry:
%x = alloca i32, i64 5, align 4
ret void
}
;.
; CHECK: attributes #[[ATTR0]] = { sanitize_memory }
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
; CHECK: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
;.
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_memory", i32 1}
;.
28 changes: 28 additions & 0 deletions llvm/test/Instrumentation/ThreadSanitizer/tsan-pass-second-run.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
; RUN: opt < %s -passes=tsan-module,tsan-module -S | FileCheck %s

target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"

declare void @can_throw()
declare void @cannot_throw() nounwind

;.
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tsan.module_ctor], section "llvm.metadata"
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tsan.module_ctor, ptr null }]
;.
define i32 @func1() sanitize_thread {
; CHECK: Function Attrs: sanitize_thread
; CHECK-LABEL: define i32 @func1
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: call void @can_throw()
; CHECK-NEXT: ret i32 0
;
call void @can_throw()
ret i32 0
}
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
; CHECK: attributes #[[ATTR1]] = { sanitize_thread }
;.
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_thread", i32 1}
;.
Loading