Skip to content

Commit 3c7c677

Browse files
committed
[Sanitizer] Make sanitizer passes idempotent.
1 parent 120740b commit 3c7c677

File tree

14 files changed

+244
-2
lines changed

14 files changed

+244
-2
lines changed

clang/test/CodeGenObjC/no-sanitize.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
@interface I0 @end
44
@implementation I0
5-
// CHECK-NOT: sanitize_address
5+
// CHECK-NOT: Function Attrs: sanitize_address
66
- (void) im0: (int) a0 __attribute__((no_sanitize("address"))) {
77
int (^blockName)(void) = ^int(void) { return 0; };
88
}

llvm/include/llvm/Transforms/Instrumentation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class Triple;
3030
class OptimizationRemarkEmitter;
3131
class Comdat;
3232
class CallBase;
33+
class Module;
34+
35+
/// Check if module has flag attached, if not add the flag.
36+
bool checkIfAlreadyInstrumented(Module &M, StringRef Flag);
3337

3438
/// Instrumentation passes often insert conditional checks into entry blocks.
3539
/// Call this function before splitting the entry block to move instructions

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,11 @@ AddressSanitizerPass::AddressSanitizerPass(
12511251

12521252
PreservedAnalyses AddressSanitizerPass::run(Module &M,
12531253
ModuleAnalysisManager &MAM) {
1254+
// Return early if nosanitize_address module flag is present for the module.
1255+
// This implies that asan pass has already run before.
1256+
if (checkIfAlreadyInstrumented(M, "nosanitize_address"))
1257+
return PreservedAnalyses::all();
1258+
12541259
ModuleAddressSanitizer ModuleSanitizer(
12551260
M, Options.InsertVersionCheck, Options.CompileKernel, Options.Recover,
12561261
UseGlobalGC, UseOdrIndicator, DestructorKind, ConstructorKind);

llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,9 @@ void DFSanVisitor::visitPHINode(PHINode &PN) {
34733473

34743474
PreservedAnalyses DataFlowSanitizerPass::run(Module &M,
34753475
ModuleAnalysisManager &AM) {
3476+
// Return early if nosanitize_dataflow module flag is present for the module.
3477+
if (checkIfAlreadyInstrumented(M, "nosanitize_dataflow"))
3478+
return PreservedAnalyses::all();
34763479
auto GetTLI = [&](Function &F) -> TargetLibraryInfo & {
34773480
auto &FAM =
34783481
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();

llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "llvm/Support/RandomNumberGenerator.h"
5858
#include "llvm/Support/raw_ostream.h"
5959
#include "llvm/TargetParser/Triple.h"
60+
#include "llvm/Transforms/Instrumentation.h"
6061
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
6162
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
6263
#include "llvm/Transforms/Utils/Local.h"
@@ -455,6 +456,9 @@ class HWAddressSanitizer {
455456

456457
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
457458
ModuleAnalysisManager &MAM) {
459+
// Return early if nosanitize_hwaddress module flag is present for the module.
460+
if (checkIfAlreadyInstrumented(M, "nosanitize_hwaddress"))
461+
return PreservedAnalyses::all();
458462
const StackSafetyGlobalInfo *SSI = nullptr;
459463
auto TargetTriple = llvm::Triple(M.getTargetTriple());
460464
if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))

llvm/lib/Transforms/Instrumentation/Instrumentation.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,47 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/Transforms/Instrumentation.h"
15+
#include "llvm/IR/DiagnosticInfo.h"
16+
#include "llvm/IR/DiagnosticPrinter.h"
1517
#include "llvm/IR/IntrinsicInst.h"
1618
#include "llvm/IR/Module.h"
1719
#include "llvm/TargetParser/Triple.h"
1820

1921
using namespace llvm;
2022

23+
static cl::opt<bool> ClIgnoreRedundantInstrumentation(
24+
"ignore-redundant-instrumentation",
25+
cl::desc("Ignore redundant instrumentation"), cl::Hidden, cl::init(false));
26+
27+
namespace {
28+
/// Diagnostic information for IR instrumentation reporting.
29+
class DiagnosticInfoInstrumentation : public DiagnosticInfo {
30+
const Twine &Msg;
31+
32+
public:
33+
DiagnosticInfoInstrumentation(const Twine &DiagMsg,
34+
DiagnosticSeverity Severity = DS_Warning)
35+
: DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
36+
void print(DiagnosticPrinter &DP) const override { DP << Msg; }
37+
};
38+
} // namespace
39+
40+
/// Check if module has flag attached, if not add the flag.
41+
bool llvm::checkIfAlreadyInstrumented(Module &M, StringRef Flag) {
42+
if (M.getModuleFlag(Flag)) {
43+
if (ClIgnoreRedundantInstrumentation)
44+
return true;
45+
std::string diagInfo =
46+
"Redundant instrumentation detected, with module flag: " +
47+
std::string(Flag);
48+
M.getContext().diagnose(DiagnosticInfoInstrumentation(
49+
diagInfo, DiagnosticSeverity::DS_Warning));
50+
return true;
51+
}
52+
M.addModuleFlag(Module::ModFlagBehavior::Override, Flag, 1);
53+
return false;
54+
}
55+
2156
/// Moves I before IP. Returns new insert point.
2257
static BasicBlock::iterator moveBeforeInsertPoint(BasicBlock::iterator I, BasicBlock::iterator IP) {
2358
// If I is IP, move the insert point down.

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
#include "llvm/Support/MathExtras.h"
199199
#include "llvm/Support/raw_ostream.h"
200200
#include "llvm/TargetParser/Triple.h"
201+
#include "llvm/Transforms/Instrumentation.h"
201202
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
202203
#include "llvm/Transforms/Utils/Local.h"
203204
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -706,6 +707,9 @@ MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K,
706707

707708
PreservedAnalyses MemorySanitizerPass::run(Module &M,
708709
ModuleAnalysisManager &AM) {
710+
// Return early if nosanitize_memory module flag is present for the module.
711+
if (checkIfAlreadyInstrumented(M, "nosanitize_memory"))
712+
return PreservedAnalyses::all();
709713
bool Modified = false;
710714
if (!Options.Kernel) {
711715
insertModuleCtor(M);

llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ PreservedAnalyses ThreadSanitizerPass::run(Function &F,
191191

192192
PreservedAnalyses ModuleThreadSanitizerPass::run(Module &M,
193193
ModuleAnalysisManager &MAM) {
194+
// Return early if nosanitize_thread module flag is present for the module.
195+
if (checkIfAlreadyInstrumented(M, "nosanitize_thread"))
196+
return PreservedAnalyses::all();
194197
insertModuleCtor(M);
195198
return PreservedAnalyses::none();
196199
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
2+
; This test checks in the second run, function is not instrumented again.
3+
; RUN: opt < %s -passes=asan,asan -S | FileCheck %s
4+
5+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
6+
target triple = "x86_64-unknown-linux-gnu"
7+
8+
; Function with sanitize_address is instrumented.
9+
; Function Attrs: nounwind uwtable
10+
;.
11+
; CHECK: @___asan_globals_registered = common hidden global i64 0
12+
; CHECK: @__start_asan_globals = extern_weak hidden global i64
13+
; CHECK: @__stop_asan_globals = extern_weak hidden global i64
14+
;.
15+
define void @instr_sa(ptr %a) sanitize_address {
16+
; CHECK: Function Attrs: sanitize_address
17+
; CHECK-LABEL: define void @instr_sa(
18+
; CHECK-SAME: ptr [[A:%.*]]) #[[ATTR0:[0-9]+]] {
19+
; CHECK-NEXT: [[ENTRY:.*:]]
20+
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
21+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i64 [[TMP0]], 3
22+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 2147450880
23+
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
24+
; CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[TMP3]], align 1
25+
; CHECK-NEXT: [[TMP5:%.*]] = icmp ne i8 [[TMP4]], 0
26+
; CHECK-NEXT: br i1 [[TMP5]], label %[[BB6:.*]], label %[[BB12:.*]], !prof [[PROF1:![0-9]+]]
27+
; CHECK: [[BB6]]:
28+
; CHECK-NEXT: [[TMP7:%.*]] = and i64 [[TMP0]], 7
29+
; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[TMP7]], 3
30+
; CHECK-NEXT: [[TMP9:%.*]] = trunc i64 [[TMP8]] to i8
31+
; CHECK-NEXT: [[TMP10:%.*]] = icmp sge i8 [[TMP9]], [[TMP4]]
32+
; CHECK-NEXT: br i1 [[TMP10]], label %[[BB11:.*]], label %[[BB12]]
33+
; CHECK: [[BB11]]:
34+
; CHECK-NEXT: call void @__asan_report_load4(i64 [[TMP0]]) #[[ATTR2:[0-9]+]]
35+
; CHECK-NEXT: unreachable
36+
; CHECK: [[BB12]]:
37+
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A]], align 4
38+
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
39+
; CHECK-NEXT: store i32 [[TMP2]], ptr [[A]], align 4
40+
; CHECK-NEXT: ret void
41+
;
42+
entry:
43+
%tmp1 = load i32, ptr %a, align 4
44+
%tmp2 = add i32 %tmp1, 1
45+
store i32 %tmp2, ptr %a, align 4
46+
ret void
47+
}
48+
;.
49+
; CHECK: attributes #[[ATTR0]] = { sanitize_address }
50+
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
51+
; CHECK: attributes #[[ATTR2]] = { nomerge }
52+
;.
53+
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_address", i32 1}
54+
; CHECK: [[PROF1]] = !{!"branch_weights", i32 1, i32 1048575}
55+
;.

llvm/test/Instrumentation/AddressSanitizer/missing_dbg.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ entry:
3434
!4 = !DISubroutineType(types: !5)
3535
!5 = !{}
3636

37-
; CHECK: [[DBG]] = !DILocation(line: 0, scope: !3)
37+
; CHECK: [[DBG]] = !DILocation(line: 0, scope: !4)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: opt < %s -passes=dfsan,dfsan -S | FileCheck %s
2+
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"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
define i8 @add(i8 %a, i8 %b) {
6+
; CHECK: @add.dfsan
7+
; CHECK-DAG: %[[#ALABEL:]] = load i8, ptr @__dfsan_arg_tls, align [[ALIGN:2]]
8+
; CHECK-DAG: %[[#BLABEL:]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__dfsan_arg_tls to i64), i64 2) to ptr), align [[ALIGN]]
9+
; CHECK: %[[#UNION:]] = or i8 %[[#ALABEL]], %[[#BLABEL]]
10+
; CHECK: %c = add i8 %a, %b
11+
; CHECK: store i8 %[[#UNION]], ptr @__dfsan_retval_tls, align [[ALIGN]]
12+
; CHECK: ret i8 %c
13+
%c = add i8 %a, %b
14+
ret i8 %c
15+
}
16+
17+
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_dataflow", i32 1}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
2+
; Test basic address sanitizer instrumentation.
3+
;
4+
; RUN: opt < %s -passes=hwasan,hwasan -S | FileCheck %s
5+
6+
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"
7+
target triple = "x86_64-unknown-linux-gnu"
8+
9+
;.
10+
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @hwasan.module_ctor], section "llvm.metadata"
11+
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @hwasan.module_ctor, ptr @hwasan.module_ctor }]
12+
; CHECK: @__start_hwasan_globals = external hidden constant [0 x i8]
13+
; CHECK: @__stop_hwasan_globals = external hidden constant [0 x i8]
14+
; 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
15+
; CHECK: @hwasan.dummy.global = private constant [0 x i8] zeroinitializer, section "hwasan_globals", comdat($hwasan.module_ctor), !associated [[META0:![0-9]+]]
16+
; CHECK: @__hwasan_tls = external thread_local(initialexec) global i64
17+
; CHECK: @llvm.compiler.used = appending global [3 x ptr] [ptr @hwasan.note, ptr @hwasan.dummy.global, ptr @__hwasan_tls], section "llvm.metadata"
18+
; CHECK: @__hwasan_shadow = external global [0 x i8]
19+
;.
20+
define i8 @test_load8(ptr %a) sanitize_hwaddress {
21+
; CHECK: Function Attrs: sanitize_hwaddress
22+
; CHECK-LABEL: define i8 @test_load8
23+
; CHECK-SAME: (ptr [[A:%.*]]) #[[ATTR0:[0-9]+]] {
24+
; CHECK-NEXT: entry:
25+
; CHECK-NEXT: [[DOTHWASAN_SHADOW:%.*]] = call ptr asm "", "=r,0"(ptr null)
26+
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[A]] to i64
27+
; CHECK-NEXT: call void @__hwasan_load1(i64 [[TMP0]])
28+
; CHECK-NEXT: [[B:%.*]] = load i8, ptr [[A]], align 4
29+
; CHECK-NEXT: ret i8 [[B]]
30+
;
31+
entry:
32+
%b = load i8, ptr %a, align 4
33+
ret i8 %b
34+
}
35+
;.
36+
; CHECK: attributes #[[ATTR0]] = { sanitize_hwaddress }
37+
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
38+
;.
39+
; CHECK: [[META0]] = !{ptr @hwasan.note}
40+
; CHECK: [[META1:![0-9]+]] = !{i32 4, !"nosanitize_hwaddress", i32 1}
41+
;.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
2+
; This test checks in the second run, function is not instrumented again.
3+
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan,msan | FileCheck %s
4+
5+
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"
6+
target triple = "x86_64-unknown-linux-gnu"
7+
8+
;.
9+
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @msan.module_ctor], section "llvm.metadata"
10+
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @msan.module_ctor, ptr null }]
11+
; CHECK: @__msan_retval_tls = external thread_local(initialexec) global [100 x i64]
12+
; CHECK: @__msan_retval_origin_tls = external thread_local(initialexec) global i32
13+
; CHECK: @__msan_param_tls = external thread_local(initialexec) global [100 x i64]
14+
; CHECK: @__msan_param_origin_tls = external thread_local(initialexec) global [200 x i32]
15+
; CHECK: @__msan_va_arg_tls = external thread_local(initialexec) global [100 x i64]
16+
; CHECK: @__msan_va_arg_origin_tls = external thread_local(initialexec) global [200 x i32]
17+
; CHECK: @__msan_va_arg_overflow_size_tls = external thread_local(initialexec) global i64
18+
;.
19+
define void @array() sanitize_memory {
20+
; CHECK: Function Attrs: sanitize_memory
21+
; CHECK-LABEL: define void @array(
22+
; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
23+
; CHECK-NEXT: [[ENTRY:.*:]]
24+
; CHECK-NEXT: call void @llvm.donothing()
25+
; CHECK-NEXT: [[X:%.*]] = alloca i32, i64 5, align 4
26+
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[X]] to i64
27+
; CHECK-NEXT: [[TMP1:%.*]] = xor i64 [[TMP0]], 87960930222080
28+
; CHECK-NEXT: [[TMP2:%.*]] = inttoptr i64 [[TMP1]] to ptr
29+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[TMP2]], i8 -1, i64 20, i1 false)
30+
; CHECK-NEXT: ret void
31+
;
32+
entry:
33+
%x = alloca i32, i64 5, align 4
34+
ret void
35+
}
36+
;.
37+
; CHECK: attributes #[[ATTR0]] = { sanitize_memory }
38+
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind }
39+
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
40+
; CHECK: attributes #[[ATTR3:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: write) }
41+
;.
42+
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_memory", i32 1}
43+
;.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals --version 2
2+
; RUN: opt < %s -passes=tsan-module,tsan-module -S | FileCheck %s
3+
4+
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"
5+
6+
declare void @can_throw()
7+
declare void @cannot_throw() nounwind
8+
9+
;.
10+
; CHECK: @llvm.used = appending global [1 x ptr] [ptr @tsan.module_ctor], section "llvm.metadata"
11+
; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @tsan.module_ctor, ptr null }]
12+
;.
13+
define i32 @func1() sanitize_thread {
14+
; CHECK: Function Attrs: sanitize_thread
15+
; CHECK-LABEL: define i32 @func1
16+
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
17+
; CHECK-NEXT: call void @can_throw()
18+
; CHECK-NEXT: ret i32 0
19+
;
20+
call void @can_throw()
21+
ret i32 0
22+
}
23+
;.
24+
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nounwind }
25+
; CHECK: attributes #[[ATTR1]] = { sanitize_thread }
26+
;.
27+
; CHECK: [[META0:![0-9]+]] = !{i32 4, !"nosanitize_thread", i32 1}
28+
;.

0 commit comments

Comments
 (0)