Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -78,8 +78,8 @@ static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; -// TODO(wwchrome): Experimental for asan Win64, may change. -static const uint64_t kWindowsShadowOffset64 = 0x1ULL << 45; // 32TB. +// The shadow memory space is dynamically allocated. +static const uint64_t kWindowsShadowOffset64 = ~(uint64_t)0; static const size_t kMinStackMallocSize = 1 << 6; // 64B static const size_t kMaxStackMallocSize = 1 << 16; // 64K @@ -121,6 +121,9 @@ static const char *const kAsanOptionDetectUseAfterReturn = "__asan_option_detect_stack_use_after_return"; +static const char *const kAsanShadowMemoryDynamicAddress = + "__asan_shadow_memory_dynamic_address"; + static const char *const kAsanAllocaPoison = "__asan_alloca_poison"; static const char *const kAsanAllocasUnpoison = "__asan_allocas_unpoison"; @@ -153,6 +156,11 @@ "asan-always-slow-path", cl::desc("use instrumentation with slow path for all accesses"), cl::Hidden, cl::init(false)); +static cl::opt ClForceDynamicShadow( + "asan-force-dynamic-shadow", + cl::desc("Load shadow address into a local variable for each function"), + cl::Hidden, cl::init(false)); + // This flag limits the number of instructions to be instrumented // in any given BB. Normally, this should be set to unlimited (INT_MAX), // but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary @@ -433,7 +441,8 @@ // we could OR the constant in a single instruction, but it's more // efficient to load it once and use indexed addressing. Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ - && !(Mapping.Offset & (Mapping.Offset - 1)); + && !(Mapping.Offset & (Mapping.Offset - 1)) + && Mapping.Offset != ~(uint64_t)0; return Mapping; } @@ -497,7 +506,9 @@ void instrumentMemIntrinsic(MemIntrinsic *MI); Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); bool runOnFunction(Function &F) override; - bool maybeInsertAsanInitAtFunctionEntry(Function &F); + void maybeInsertAsanInitAtFunctionEntry(Function &F); + void maybeInsertDynamicShadowAtFunctionEntry(Function &F); + void maybeFinalizeDynamicShadow(Function &F); void markEscapedLocalAllocas(Function &F); bool doInitialization(Module &M) override; bool doFinalization(Module &M) override; @@ -544,6 +555,7 @@ Function *AsanMemoryAccessCallbackSized[2][2]; Function *AsanMemmove, *AsanMemcpy, *AsanMemset; InlineAsm *EmptyAsm; + AllocaInst *LocalDynamicShadow; GlobalsMetadata GlobalsMD; DenseMap ProcessedAllocas; @@ -891,10 +903,15 @@ Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); if (Mapping.Offset == 0) return Shadow; // (Shadow >> scale) | offset + Value* ShadowBase; + if (LocalDynamicShadow) + ShadowBase = IRB.CreateLoad(LocalDynamicShadow); + else + ShadowBase = ConstantInt::get(IntptrTy, Mapping.Offset); if (Mapping.OrShadowOffset) - return IRB.CreateOr(Shadow, ConstantInt::get(IntptrTy, Mapping.Offset)); + return IRB.CreateOr(Shadow, ShadowBase); else - return IRB.CreateAdd(Shadow, ConstantInt::get(IntptrTy, Mapping.Offset)); + return IRB.CreateAdd(Shadow, ShadowBase); } // Instrument memset/memmove/memcpy @@ -1727,7 +1744,7 @@ return false; } -bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) { +void AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) { // For each NSObject descendant having a +load method, this method is invoked // by the ObjC runtime before any of the static constructors is called. // Therefore we need to instrument such methods with a call to __asan_init @@ -1738,11 +1755,31 @@ if (F.getName().find(" load]") != std::string::npos) { IRBuilder<> IRB(&F.front(), F.front().begin()); IRB.CreateCall(AsanInitFunction, {}); - return true; } - return false; } +void AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) { + LocalDynamicShadow = nullptr; + + // Generate code only when dynamic addressing is needed. + if (!ClForceDynamicShadow && Mapping.Offset != ~(uint64_t)0) + return; + + // Create a local variable (alloca) holding the dynamic shadow address. + IRBuilder<> IRB(&F.front().front()); + LocalDynamicShadow = IRB.CreateAlloca(IntptrTy); + assert(LocalDynamicShadow->isStaticAlloca()); +} + + void AddressSanitizer::maybeFinalizeDynamicShadow(Function &F) { + if (!LocalDynamicShadow) + return; + IRBuilder<> IRB(LocalDynamicShadow->getNextNode()); + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + kAsanShadowMemoryDynamicAddress, IntptrTy); + IRB.CreateStore(IRB.CreateLoad(GlobalDynamicAddress), LocalDynamicShadow); + } + void AddressSanitizer::markEscapedLocalAllocas(Function &F) { // Find the one possible call to llvm.localescape and pre-mark allocas passed // to it as uninteresting. This assumes we haven't started processing allocas @@ -1774,17 +1811,34 @@ bool AddressSanitizer::runOnFunction(Function &F) { if (&F == AsanCtorFunction) return false; if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return false; + + // Determine if the function body must be instrumented (inserting probes). + bool instrumenting = true; + if (!F.hasFnAttribute(Attribute::SanitizeAddress)) + instrumenting = false; + if (F.getName().find("__asan_") != std::string::npos) + instrumenting = false; + + if (!ClDebugFunc.empty() && ClDebugFunc != F.getName()) + instrumenting = false; + DEBUG(dbgs() << "ASAN instrumenting:\n" << F << "\n"); - initializeCallbacks(*F.getParent()); - DT = &getAnalysis().getDomTree(); + if (instrumenting) { + initializeCallbacks(*F.getParent()); + DT = &getAnalysis().getDomTree(); + + // Generates code at function entry to retrieve the dynamic shadow address. + maybeInsertDynamicShadowAtFunctionEntry(F); + } // If needed, insert __asan_init before checking for SanitizeAddress attr. + // This function needs to be called even if the function body is not + // instrumented. maybeInsertAsanInitAtFunctionEntry(F); - if (!F.hasFnAttribute(Attribute::SanitizeAddress)) return false; - - if (!ClDebugFunc.empty() && ClDebugFunc != F.getName()) return false; + if (!instrumenting) + return false; FunctionStateRAII CleanupObj(this); @@ -1880,6 +1934,9 @@ NumInstrumented++; } + // Generate the load/store after the instrumentation is completed. + maybeFinalizeDynamicShadow(F); + bool res = NumInstrumented > 0 || ChangedStack || !NoReturnCalls.empty(); DEBUG(dbgs() << "ASAN done instrumenting: " << res << " " << F << "\n"); @@ -2270,7 +2327,7 @@ AllocaInst *FunctionStackPoisoner::findAllocaForValue(Value *V) { if (AllocaInst *AI = dyn_cast(V)) - // We're intested only in allocas we can handle. + // We're interested only in allocas we can handle. return ASan.isInterestingAlloca(*AI) ? AI : nullptr; // See if we've already calculated (or started to calculate) alloca for a // given value. Index: test/Instrumentation/AddressSanitizer/basic-msvc64.ll =================================================================== --- /dev/null +++ test/Instrumentation/AddressSanitizer/basic-msvc64.ll @@ -0,0 +1,76 @@ +; Test basic address sanitizer instrumentation. +; +; RUN: opt -asan -asan-module -S < %s | FileCheck %s + +target triple = "x86_64-pc-windows-msvc" +; CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor + +define i32 @test_load(i32* %a) sanitize_address { +; First instrumentation in the function must be to load the dynamic shadow +; address into a local variable. +; CHECK-LABEL: @test_load +; CHECK: entry: +; CHECK-NEXT: %[[ALLOCA:[^ ]*]] = alloca i64 +; CHECK-NEXT: %[[ADDRESS:[^ ]*]] = load i64, i64* @__asan_shadow_memory_dynamic_address +; CHECK-NEXT: store i64 %[[ADDRESS]], i64* %[[ALLOCA]] + +; Shadow address is loaded and added into the whole offset computation. +; CHECK: %[[SHADOW:[^ ]*]] = load i64, i64* %[[ALLOCA]] +; CHECK add i64 %{{.*}}, %[[SHADOW] ] + +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +} + +define i32 @__asan_options(i32* %a) sanitize_address { +; Asan functions are not instrumented. Asan function may be called by +; __asan_init before the shadow initialisation, which may lead to incorrect +; behavior of the instrumented code. +; CHECK-LABEL: @__asan_options +; CHECK: entry: +; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4 +; CHECK-NEXT: ret i32 %tmp1 + +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +} +; Test basic address sanitizer instrumentation. +; +; RUN: opt -asan -asan-module -S < %s | FileCheck %s + +target triple = "x86_64-pc-windows-msvc" +; CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor + +define i32 @test_load(i32* %a) sanitize_address { +; First instrumentation in the function must be to load the dynamic shadow +; address into a local variable. +; CHECK-LABEL: @test_load +; CHECK: entry: +; CHECK-NEXT: %[[ALLOCA:[^ ]*]] = alloca i64 +; CHECK-NEXT: %[[ADDRESS:[^ ]*]] = load i64, i64* @__asan_shadow_memory_dynamic_address +; CHECK-NEXT: store i64 %[[ADDRESS]], i64* %[[ALLOCA]] + +; Shadow address is loaded and added into the whole offset computation. +; CHECK: %[[SHADOW:[^ ]*]] = load i64, i64* %[[ALLOCA]] +; CHECK add i64 %{{.*}}, %[[SHADOW] ] + +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +} + +define i32 @__asan_options(i32* %a) sanitize_address { +; Asan functions are not instrumented. Asan function may be called by +; __asan_init before the shadow initialisation, which may lead to incorrect +; behavior of the instrumented code. +; CHECK-LABEL: @__asan_options +; CHECK: entry: +; CHECK-NEXT: %tmp1 = load i32, i32* %a, align 4 +; CHECK-NEXT: ret i32 %tmp1 + +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +}