llvm.org GIT mirror llvm / ccb3bb9
[sanitizers] Disable target-specific lowering of string functions. CodeGen has hooks that allow targets to emit specialized code instead of calls to memcmp, memchr, strcpy, stpcpy, strcmp, strlen, strnlen. When ASan/MSan/TSan/ESan is in use, this sidesteps its interceptors, resulting in uninstrumented memory accesses. To avoid that, make these sanitizers mark the calls as nobuiltin. Differential Revision: http://reviews.llvm.org/D19781 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273083 91177308-0d34-0410-b5e6-96231b3b80d8 Marcin Koscielnicki 4 years ago
10 changed file(s) with 224 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
2929 class Function;
3030 class BranchInst;
3131 class Instruction;
32 class CallInst;
3233 class DbgDeclareInst;
3334 class StoreInst;
3435 class LoadInst;
353354 Instruction *I, bool MatchBSwaps, bool MatchBitReversals,
354355 SmallVectorImpl &InsertedInsts);
355356
357 //===----------------------------------------------------------------------===//
358 // Sanitizer utilities
359 //
360
361 /// Given a CallInst, check if it calls a string function known to CodeGen,
362 /// and mark it with NoBuiltin if so. To be used by sanitizers that intend
363 /// to intercept string functions and want to avoid converting them to target
364 /// specific instructions.
365 void maybeMarkSanitizerLibraryCallNoBuiltin(CallInst *CI,
366 const TargetLibraryInfo *TLI);
367
356368 } // End llvm namespace
357369
358370 #endif
17641764 bool IsWrite;
17651765 unsigned Alignment;
17661766 uint64_t TypeSize;
1767 const TargetLibraryInfo *TLI =
1768 &getAnalysis().getTLI();
17671769
17681770 // Fill the set of memory operations to instrument.
17691771 for (auto &BB : F) {
17921794 TempsToInstrument.clear();
17931795 if (CS.doesNotReturn()) NoReturnCalls.push_back(CS.getInstruction());
17941796 }
1797 if (CallInst *CI = dyn_cast(&Inst))
1798 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
17951799 continue;
17961800 }
17971801 ToInstrument.push_back(&Inst);
18041808 CompileKernel ||
18051809 (ClInstrumentationWithCallsThreshold >= 0 &&
18061810 ToInstrument.size() > (unsigned)ClInstrumentationWithCallsThreshold);
1807 const TargetLibraryInfo *TLI =
1808 &getAnalysis().getTLI();
18091811 const DataLayout &DL = F.getParent()->getDataLayout();
18101812 ObjectSizeOffsetVisitor ObjSizeVis(DL, TLI, F.getContext(),
18111813 /*RoundToAlign=*/true);
2222 #include "llvm/ADT/SmallVector.h"
2323 #include "llvm/ADT/Statistic.h"
2424 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Analysis/TargetLibraryInfo.h"
2526 #include "llvm/IR/Function.h"
2627 #include "llvm/IR/IRBuilder.h"
2728 #include "llvm/IR/IntrinsicInst.h"
3132 #include "llvm/Support/Debug.h"
3233 #include "llvm/Support/raw_ostream.h"
3334 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
35 #include "llvm/Transforms/Utils/Local.h"
3436 #include "llvm/Transforms/Utils/ModuleUtils.h"
3537
3638 using namespace llvm;
148150 const EfficiencySanitizerOptions &Opts = EfficiencySanitizerOptions())
149151 : ModulePass(ID), Options(OverrideOptionsFromCL(Opts)) {}
150152 const char *getPassName() const override;
153 void getAnalysisUsage(AnalysisUsage &AU) const override;
151154 bool runOnModule(Module &M) override;
152155 static char ID;
153156
198201 } // namespace
199202
200203 char EfficiencySanitizer::ID = 0;
201 INITIALIZE_PASS(EfficiencySanitizer, "esan",
202 "EfficiencySanitizer: finds performance issues.", false, false)
204 INITIALIZE_PASS_BEGIN(
205 EfficiencySanitizer, "esan",
206 "EfficiencySanitizer: finds performance issues.", false, false)
207 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
208 INITIALIZE_PASS_END(
209 EfficiencySanitizer, "esan",
210 "EfficiencySanitizer: finds performance issues.", false, false)
203211
204212 const char *EfficiencySanitizer::getPassName() const {
205213 return "EfficiencySanitizer";
214 }
215
216 void EfficiencySanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
217 AU.addRequired();
206218 }
207219
208220 ModulePass *
543555 SmallVector GetElementPtrs;
544556 bool Res = false;
545557 const DataLayout &DL = M.getDataLayout();
558 const TargetLibraryInfo *TLI =
559 &getAnalysis().getTLI();
546560
547561 for (auto &BB : F) {
548562 for (auto &Inst : BB) {
554568 MemIntrinCalls.push_back(&Inst);
555569 else if (isa(Inst))
556570 GetElementPtrs.push_back(&Inst);
571 else if (CallInst *CI = dyn_cast(&Inst))
572 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
557573 }
558574 }
559575
316316 TrackOrigins(std::max(TrackOrigins, (int)ClTrackOrigins)),
317317 WarningFn(nullptr) {}
318318 const char *getPassName() const override { return "MemorySanitizer"; }
319 void getAnalysisUsage(AnalysisUsage &AU) const override {
320 AU.addRequired();
321 }
319322 bool runOnFunction(Function &F) override;
320323 bool doInitialization(Module &M) override;
321324 static char ID; // Pass identification, replacement for typeid.
383386 } // anonymous namespace
384387
385388 char MemorySanitizer::ID = 0;
386 INITIALIZE_PASS(MemorySanitizer, "msan",
387 "MemorySanitizer: detects uninitialized reads.",
388 false, false)
389 INITIALIZE_PASS_BEGIN(
390 MemorySanitizer, "msan",
391 "MemorySanitizer: detects uninitialized reads.", false, false)
392 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
393 INITIALIZE_PASS_END(
394 MemorySanitizer, "msan",
395 "MemorySanitizer: detects uninitialized reads.", false, false)
389396
390397 FunctionPass *llvm::createMemorySanitizerPass(int TrackOrigins) {
391398 return new MemorySanitizer(TrackOrigins);
617624 SmallVector ShadowPHINodes, OriginPHINodes;
618625 ValueMap ShadowMap, OriginMap;
619626 std::unique_ptr VAHelper;
627 const TargetLibraryInfo *TLI;
620628
621629 // The following flags disable parts of MSan instrumentation based on
622630 // blacklist contents and command-line options.
646654 // FIXME: Consider using SpecialCaseList to specify a list of functions that
647655 // must always return fully initialized values. For now, we hardcode "main".
648656 CheckReturnValue = SanitizeFunction && (F.getName() == "main");
657 TLI = &MS.getAnalysis().getTLI();
649658
650659 DEBUG(if (!InsertChecks)
651660 dbgs() << "MemorySanitizer is not inserting checks into '"
25282537 AttributeSet::FunctionIndex,
25292538 B));
25302539 }
2540
2541 maybeMarkSanitizerLibraryCallNoBuiltin(Call, TLI);
25312542 }
25322543 IRBuilder<> IRB(&I);
25332544
2525 #include "llvm/ADT/Statistic.h"
2626 #include "llvm/ADT/StringExtras.h"
2727 #include "llvm/Analysis/CaptureTracking.h"
28 #include "llvm/Analysis/TargetLibraryInfo.h"
2829 #include "llvm/Analysis/ValueTracking.h"
2930 #include "llvm/IR/DataLayout.h"
3031 #include "llvm/IR/Function.h"
4142 #include "llvm/Support/MathExtras.h"
4243 #include "llvm/Support/raw_ostream.h"
4344 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
45 #include "llvm/Transforms/Utils/Local.h"
4446 #include "llvm/Transforms/Utils/ModuleUtils.h"
4547
4648 using namespace llvm;
8183 struct ThreadSanitizer : public FunctionPass {
8284 ThreadSanitizer() : FunctionPass(ID) {}
8385 const char *getPassName() const override;
86 void getAnalysisUsage(AnalysisUsage &AU) const override;
8487 bool runOnFunction(Function &F) override;
8588 bool doInitialization(Module &M) override;
8689 static char ID; // Pass identification, replacement for typeid.
121124 } // namespace
122125
123126 char ThreadSanitizer::ID = 0;
124 INITIALIZE_PASS(ThreadSanitizer, "tsan",
127 INITIALIZE_PASS_BEGIN(
128 ThreadSanitizer, "tsan",
125129 "ThreadSanitizer: detects data races.",
126130 false, false)
131 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
132 INITIALIZE_PASS_END(
133 ThreadSanitizer, "tsan",
134 "ThreadSanitizer: detects data races.",
135 false, false)
127136
128137 const char *ThreadSanitizer::getPassName() const {
129138 return "ThreadSanitizer";
139 }
140
141 void ThreadSanitizer::getAnalysisUsage(AnalysisUsage &AU) const {
142 AU.addRequired();
130143 }
131144
132145 FunctionPass *llvm::createThreadSanitizerPass() {
367380 bool HasCalls = false;
368381 bool SanitizeFunction = F.hasFnAttribute(Attribute::SanitizeThread);
369382 const DataLayout &DL = F.getParent()->getDataLayout();
383 const TargetLibraryInfo *TLI =
384 &getAnalysis().getTLI();
370385
371386 // Traverse all instructions, collect loads/stores/returns, check for calls.
372387 for (auto &BB : F) {
378393 else if (isa(Inst))
379394 RetVec.push_back(&Inst);
380395 else if (isa(Inst) || isa(Inst)) {
396 if (CallInst *CI = dyn_cast(&Inst))
397 maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI);
381398 if (isa(Inst))
382399 MemIntrinCalls.push_back(&Inst);
383400 HasCalls = true;
19411941 InsertedInsts.push_back(CallInst::Create(F, Res->Provider, "rev", I));
19421942 return true;
19431943 }
1944
1945 // CodeGen has special handling for some string functions that may replace
1946 // them with target-specific intrinsics. Since that'd skip our interceptors
1947 // in ASan/MSan/TSan/DFSan, and thus make us miss some memory accesses,
1948 // we mark affected calls as NoBuiltin, which will disable optimization
1949 // in CodeGen.
1950 void llvm::maybeMarkSanitizerLibraryCallNoBuiltin(CallInst *CI,
1951 const TargetLibraryInfo *TLI) {
1952 Function *F = CI->getCalledFunction();
1953 LibFunc::Func Func;
1954 if (!F || F->hasLocalLinkage() || !F->hasName() ||
1955 !TLI->getLibFunc(F->getName(), Func))
1956 return;
1957 switch (Func) {
1958 default: break;
1959 case LibFunc::memcmp:
1960 case LibFunc::memchr:
1961 case LibFunc::strcpy:
1962 case LibFunc::stpcpy:
1963 case LibFunc::strcmp:
1964 case LibFunc::strlen:
1965 case LibFunc::strnlen:
1966 CI->addAttribute(AttributeSet::FunctionIndex, Attribute::NoBuiltin);
1967 break;
1968 }
1969 }
0 ; Test marking string functions as nobuiltin in address sanitizer.
1 ;
2 ; RUN: opt < %s -asan -S | FileCheck %s
3 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"
4 target triple = "x86_64-unknown-linux-gnu"
5
6 declare i8* @memchr(i8* %a, i32 %b, i64 %c)
7 declare i32 @memcmp(i8* %a, i8* %b, i64 %c)
8 declare i32 @strcmp(i8* %a, i8* %b)
9 declare i8* @strcpy(i8* %a, i8* %b)
10 declare i8* @stpcpy(i8* %a, i8* %b)
11 declare i64 @strlen(i8* %a)
12 declare i64 @strnlen(i8* %a, i64 %b)
13
14 ; CHECK: call{{.*}}@memchr{{.*}} #[[ATTR:[0-9]+]]
15 ; CHECK: call{{.*}}@memcmp{{.*}} #[[ATTR]]
16 ; CHECK: call{{.*}}@strcmp{{.*}} #[[ATTR]]
17 ; CHECK: call{{.*}}@strcpy{{.*}} #[[ATTR]]
18 ; CHECK: call{{.*}}@stpcpy{{.*}} #[[ATTR]]
19 ; CHECK: call{{.*}}@strlen{{.*}} #[[ATTR]]
20 ; CHECK: call{{.*}}@strnlen{{.*}} #[[ATTR]]
21 ; attributes #[[ATTR]] = { nobuiltin }
22
23 define void @f1(i8* %a, i8* %b) nounwind uwtable sanitize_address {
24 tail call i8* @memchr(i8* %a, i32 1, i64 12)
25 tail call i32 @memcmp(i8* %a, i8* %b, i64 12)
26 tail call i32 @strcmp(i8* %a, i8* %b)
27 tail call i8* @strcpy(i8* %a, i8* %b)
28 tail call i8* @stpcpy(i8* %a, i8* %b)
29 tail call i64 @strlen(i8* %a)
30 tail call i64 @strnlen(i8* %a, i64 12)
31 ret void
32 }
0 ; Test marking string functions as nobuiltin in efficiency sanitizer.
1 ;
2 ; RUN: opt < %s -esan -S | FileCheck %s
3 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"
4 target triple = "x86_64-unknown-linux-gnu"
5
6 declare i8* @memchr(i8* %a, i32 %b, i64 %c)
7 declare i32 @memcmp(i8* %a, i8* %b, i64 %c)
8 declare i32 @strcmp(i8* %a, i8* %b)
9 declare i8* @strcpy(i8* %a, i8* %b)
10 declare i8* @stpcpy(i8* %a, i8* %b)
11 declare i64 @strlen(i8* %a)
12 declare i64 @strnlen(i8* %a, i64 %b)
13
14 ; CHECK: call{{.*}}@memchr{{.*}} #[[ATTR:[0-9]+]]
15 ; CHECK: call{{.*}}@memcmp{{.*}} #[[ATTR]]
16 ; CHECK: call{{.*}}@strcmp{{.*}} #[[ATTR]]
17 ; CHECK: call{{.*}}@strcpy{{.*}} #[[ATTR]]
18 ; CHECK: call{{.*}}@stpcpy{{.*}} #[[ATTR]]
19 ; CHECK: call{{.*}}@strlen{{.*}} #[[ATTR]]
20 ; CHECK: call{{.*}}@strnlen{{.*}} #[[ATTR]]
21 ; attributes #[[ATTR]] = { nobuiltin }
22
23 define void @f1(i8* %a, i8* %b) nounwind uwtable {
24 tail call i8* @memchr(i8* %a, i32 1, i64 12)
25 tail call i32 @memcmp(i8* %a, i8* %b, i64 12)
26 tail call i32 @strcmp(i8* %a, i8* %b)
27 tail call i8* @strcpy(i8* %a, i8* %b)
28 tail call i8* @stpcpy(i8* %a, i8* %b)
29 tail call i64 @strlen(i8* %a)
30 tail call i64 @strnlen(i8* %a, i64 12)
31 ret void
32 }
0 ; Test marking string functions as nobuiltin in memory sanitizer.
1 ;
2 ; RUN: opt < %s -msan -S | FileCheck %s
3 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"
4 target triple = "x86_64-unknown-linux-gnu"
5
6 declare i8* @memchr(i8* %a, i32 %b, i64 %c)
7 declare i32 @memcmp(i8* %a, i8* %b, i64 %c)
8 declare i32 @strcmp(i8* %a, i8* %b)
9 declare i8* @strcpy(i8* %a, i8* %b)
10 declare i8* @stpcpy(i8* %a, i8* %b)
11 declare i64 @strlen(i8* %a)
12 declare i64 @strnlen(i8* %a, i64 %b)
13
14 ; CHECK: call{{.*}}@memchr{{.*}} #[[ATTR:[0-9]+]]
15 ; CHECK: call{{.*}}@memcmp{{.*}} #[[ATTR]]
16 ; CHECK: call{{.*}}@strcmp{{.*}} #[[ATTR]]
17 ; CHECK: call{{.*}}@strcpy{{.*}} #[[ATTR]]
18 ; CHECK: call{{.*}}@stpcpy{{.*}} #[[ATTR]]
19 ; CHECK: call{{.*}}@strlen{{.*}} #[[ATTR]]
20 ; CHECK: call{{.*}}@strnlen{{.*}} #[[ATTR]]
21 ; attributes #[[ATTR]] = { nobuiltin }
22
23 define void @f1(i8* %a, i8* %b) nounwind uwtable sanitize_memory {
24 tail call i8* @memchr(i8* %a, i32 1, i64 12)
25 tail call i32 @memcmp(i8* %a, i8* %b, i64 12)
26 tail call i32 @strcmp(i8* %a, i8* %b)
27 tail call i8* @strcpy(i8* %a, i8* %b)
28 tail call i8* @stpcpy(i8* %a, i8* %b)
29 tail call i64 @strlen(i8* %a)
30 tail call i64 @strnlen(i8* %a, i64 12)
31 ret void
32 }
0 ; Test marking string functions as nobuiltin in thread sanitizer.
1 ;
2 ; RUN: opt < %s -tsan -S | FileCheck %s
3 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"
4 target triple = "x86_64-unknown-linux-gnu"
5
6 declare i8* @memchr(i8* %a, i32 %b, i64 %c)
7 declare i32 @memcmp(i8* %a, i8* %b, i64 %c)
8 declare i32 @strcmp(i8* %a, i8* %b)
9 declare i8* @strcpy(i8* %a, i8* %b)
10 declare i8* @stpcpy(i8* %a, i8* %b)
11 declare i64 @strlen(i8* %a)
12 declare i64 @strnlen(i8* %a, i64 %b)
13
14 ; CHECK: call{{.*}}@memchr{{.*}} #[[ATTR:[0-9]+]]
15 ; CHECK: call{{.*}}@memcmp{{.*}} #[[ATTR]]
16 ; CHECK: call{{.*}}@strcmp{{.*}} #[[ATTR]]
17 ; CHECK: call{{.*}}@strcpy{{.*}} #[[ATTR]]
18 ; CHECK: call{{.*}}@stpcpy{{.*}} #[[ATTR]]
19 ; CHECK: call{{.*}}@strlen{{.*}} #[[ATTR]]
20 ; CHECK: call{{.*}}@strnlen{{.*}} #[[ATTR]]
21 ; attributes #[[ATTR]] = { nobuiltin }
22
23 define void @f1(i8* %a, i8* %b) nounwind uwtable sanitize_thread {
24 tail call i8* @memchr(i8* %a, i32 1, i64 12)
25 tail call i32 @memcmp(i8* %a, i8* %b, i64 12)
26 tail call i32 @strcmp(i8* %a, i8* %b)
27 tail call i8* @strcpy(i8* %a, i8* %b)
28 tail call i8* @stpcpy(i8* %a, i8* %b)
29 tail call i64 @strlen(i8* %a)
30 tail call i64 @strnlen(i8* %a, i64 12)
31 ret void
32 }