Index: include/llvm/Transforms/Instrumentation/AddressSanitizer.h =================================================================== --- include/llvm/Transforms/Instrumentation/AddressSanitizer.h +++ include/llvm/Transforms/Instrumentation/AddressSanitizer.h @@ -100,13 +100,17 @@ public: explicit AddressSanitizerPass(bool CompileKernel = false, bool Recover = false, - bool UseAfterScope = false); + bool UseAfterScope = false, + bool InvalidPointerCmp = false, + bool InvalidPointerSub = false); PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); private: bool CompileKernel; bool Recover; bool UseAfterScope; + bool InvalidPointerCmp; + bool InvalidPointerSub; }; /// Public interface to the address sanitizer module pass for instrumenting code @@ -131,9 +135,10 @@ }; // Insert AddressSanitizer (address sanity checking) instrumentation -FunctionPass *createAddressSanitizerFunctionPass(bool CompileKernel = false, - bool Recover = false, - bool UseAfterScope = false); +FunctionPass *createAddressSanitizerFunctionPass( + bool CompileKernel = false, bool Recover = false, + bool UseAfterScope = false, bool InvalidPointerCmp = false, + bool InvalidPointerSub = false); ModulePass *createModuleAddressSanitizerLegacyPassPass( bool CompileKernel = false, bool Recover = false, bool UseGlobalsGC = true, bool UseOdrIndicator = true); Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -275,6 +275,16 @@ cl::desc("Instrument <, <=, >, >=, - with pointer operands"), cl::Hidden, cl::init(false)); +static cl::opt ClInvalidPointerCmp( + "asan-detect-invalid-pointer-cmp", + cl::desc("Instrument <, <=, >, >= with pointer operands"), cl::Hidden, + cl::init(false)); + +static cl::opt ClInvalidPointerSub( + "asan-detect-invalid-pointer-sub", + cl::desc("Instrument - operations with pointer operands"), cl::Hidden, + cl::init(false)); + static cl::opt ClRealignStack( "asan-realign-stack", cl::desc("Realign stack to the value of this flag (power of two)"), @@ -561,8 +571,12 @@ struct AddressSanitizer { AddressSanitizer(Module &M, GlobalsMetadata &GlobalsMD, bool CompileKernel = false, bool Recover = false, - bool UseAfterScope = false) - : UseAfterScope(UseAfterScope || ClUseAfterScope), GlobalsMD(GlobalsMD) { + bool UseAfterScope = false, bool InvalidPointerCmp = false, + bool InvalidPointerSub = false) + : UseAfterScope(UseAfterScope || ClUseAfterScope), + InvalidPointerCmp(InvalidPointerCmp || ClInvalidPointerCmp), + InvalidPointerSub(InvalidPointerSub || ClInvalidPointerSub), + GlobalsMD(GlobalsMD) { this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover; this->CompileKernel = ClEnableKasan.getNumOccurrences() > 0 ? ClEnableKasan : CompileKernel; @@ -654,6 +668,8 @@ bool CompileKernel; bool Recover; bool UseAfterScope; + bool InvalidPointerCmp; + bool InvalidPointerSub; Type *IntptrTy; ShadowMapping Mapping; FunctionCallee AsanHandleNoReturnFunc; @@ -681,9 +697,12 @@ explicit AddressSanitizerLegacyPass(bool CompileKernel = false, bool Recover = false, - bool UseAfterScope = false) + bool UseAfterScope = false, + bool InvalidPointerCmp = false, + bool InvalidPointerSub = false) : FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover), - UseAfterScope(UseAfterScope) { + UseAfterScope(UseAfterScope), InvalidPointerCmp(InvalidPointerCmp), + InvalidPointerSub(InvalidPointerSub) { initializeAddressSanitizerLegacyPassPass(*PassRegistry::getPassRegistry()); } @@ -702,7 +721,7 @@ const TargetLibraryInfo *TLI = &getAnalysis().getTLI(); AddressSanitizer ASan(*F.getParent(), GlobalsMD, CompileKernel, Recover, - UseAfterScope); + UseAfterScope, InvalidPointerCmp, InvalidPointerSub); return ASan.instrumentFunction(F, TLI); } @@ -710,6 +729,8 @@ bool CompileKernel; bool Recover; bool UseAfterScope; + bool InvalidPointerCmp; + bool InvalidPointerSub; }; class ModuleAddressSanitizer { @@ -1127,9 +1148,12 @@ } AddressSanitizerPass::AddressSanitizerPass(bool CompileKernel, bool Recover, - bool UseAfterScope) + bool UseAfterScope, + bool InvalidPointerCmp, + bool InvalidPointerSub) : CompileKernel(CompileKernel), Recover(Recover), - UseAfterScope(UseAfterScope) {} + UseAfterScope(UseAfterScope), InvalidPointerCmp(InvalidPointerCmp), + InvalidPointerSub(InvalidPointerSub) {} PreservedAnalyses AddressSanitizerPass::run(Function &F, AnalysisManager &AM) { @@ -1138,7 +1162,8 @@ Module &M = *F.getParent(); if (auto *R = MAM.getCachedResult(M)) { const TargetLibraryInfo *TLI = &AM.getResult(F); - AddressSanitizer Sanitizer(M, *R, CompileKernel, Recover, UseAfterScope); + AddressSanitizer Sanitizer(M, *R, CompileKernel, Recover, UseAfterScope, + InvalidPointerCmp, InvalidPointerSub); if (Sanitizer.instrumentFunction(F, TLI)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); @@ -1187,9 +1212,12 @@ FunctionPass *llvm::createAddressSanitizerFunctionPass(bool CompileKernel, bool Recover, - bool UseAfterScope) { + bool UseAfterScope, + bool InvalidPointerCmp, + bool InvalidPointerSub) { assert(!CompileKernel || Recover); - return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope); + return new AddressSanitizerLegacyPass(CompileKernel, Recover, UseAfterScope, + InvalidPointerCmp, InvalidPointerSub); } char ModuleAddressSanitizerLegacyPass::ID = 0; @@ -1408,11 +1436,24 @@ // This is a rough heuristic; it may cause both false positives and // false negatives. The proper implementation requires cooperation with // the frontend. -static bool isInterestingPointerComparisonOrSubtraction(Instruction *I) { +static bool isInterestingPointerComparison(Instruction *I) { if (ICmpInst *Cmp = dyn_cast(I)) { - if (!Cmp->isRelational()) return false; - } else if (BinaryOperator *BO = dyn_cast(I)) { - if (BO->getOpcode() != Instruction::Sub) return false; + if (!Cmp->isRelational()) + return false; + } else { + return false; + } + return isPointerOperand(I->getOperand(0)) && + isPointerOperand(I->getOperand(1)); +} + +// This is a rough heuristic; it may cause both false positives and +// false negatives. The proper implementation requires cooperation with +// the frontend. +static bool isInterestingPointerSubtraction(Instruction *I) { + if (BinaryOperator *BO = dyn_cast(I)) { + if (BO->getOpcode() != Instruction::Sub) + return false; } else { return false; } @@ -2619,8 +2660,10 @@ continue; // We've seen this temp in the current BB. } } - } else if (ClInvalidPointerPairs && - isInterestingPointerComparisonOrSubtraction(&Inst)) { + } else if (((ClInvalidPointerPairs || InvalidPointerCmp) && + isInterestingPointerComparison(&Inst)) || + ((ClInvalidPointerPairs || InvalidPointerSub) && + isInterestingPointerSubtraction(&Inst))) { PointerComparisonsOrSubtracts.push_back(&Inst); continue; } else if (isa(Inst)) { Index: test/Instrumentation/AddressSanitizer/asan-detect-invalid-pointer-pair.ll =================================================================== --- /dev/null +++ test/Instrumentation/AddressSanitizer/asan-detect-invalid-pointer-pair.ll @@ -0,0 +1,33 @@ +; RUN: opt < %s -asan -asan-detect-invalid-pointer-cmp -S \ +; RUN: | FileCheck %s -check-prefix=CMP -check-prefix=NOSUB +; RUN: opt < %s -asan -asan-detect-invalid-pointer-sub -S \ +; RUN: | FileCheck %s -check-prefix=SUB -check-prefix=NOCMP +; RUN: opt < %s -asan -asan-detect-invalid-pointer-pair -S \ +; RUN: | FileCheck %s -check-prefix=CMP -check-prefix=SUB +; Support instrumentation of invalid pointer pair detection. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define i32 @mycmp(i8* %p, i8* %q) sanitize_address { +; ALL-LABEL: @mycmp +; NOCMP-NOT: call void @__sanitizer_ptr_cmp +; CMP: [[P:%[0-9A-Za-z]+]] = ptrtoint i8* %p to i64 +; CMP: [[Q:%[0-9A-Za-z]+]] = ptrtoint i8* %q to i64 + %x = icmp ule i8* %p, %q +; CMP: call void @__sanitizer_ptr_cmp(i64 [[P]], i64 [[Q]]) + %y = zext i1 %x to i32 + ret i32 %y +} + +define i32 @mysub(i8* %p, i8* %q) sanitize_address { +; ALL-LABEL: @mysub +; NOSUB-NOT: call void @__sanitizer_ptr_sub +; SUB: [[P:%[0-9A-Za-z]+]] = ptrtoint i8* %p to i64 +; SUB: [[Q:%[0-9A-Za-z]+]] = ptrtoint i8* %q to i64 + %x = ptrtoint i8* %p to i64 + %y = ptrtoint i8* %q to i64 + %z = sub i64 %x, %y +; SUB: call void @__sanitizer_ptr_sub(i64 [[P]], i64 [[Q]]) + %w = trunc i64 %z to i32 + ret i32 %w +}