diff --git a/clang/test/CodeGen/asan-globals.cpp b/clang/test/CodeGen/asan-globals.cpp --- a/clang/test/CodeGen/asan-globals.cpp +++ b/clang/test/CodeGen/asan-globals.cpp @@ -12,26 +12,31 @@ int __attribute__((no_sanitize("address"))) attributed_global; int blacklisted_global; int __attribute__ ((section("__DATA, __common"))) sectioned_global; +char large_array[100]; +char zero_size[0]; // Ensure the redzone size calculation can deal with size==0. void func() { static int static_var = 0; const char *literal = "Hello, world!"; } +// ASAN-CHECK: @large_array = global { [100 x i8], [60 x i8] } +// KASAN-CHECK: @large_array = global { [100 x i8], [100 x i8] } + // CHECK-LABEL: define internal void @asan.module_ctor // ASAN-NEXT: call void @__asan_init // ASAN-NEXT: call void @__asan_version_mismatch_check // KASAN-NOT: call void @__asan_init // KASAN-NOT: call void @__asan_version_mismatch_check -// ASAN-NEXT: call void @__asan_register_globals({{.*}}, i{{32|64}} 6) -// KASAN-NEXT: call void @__asan_register_globals({{.*}}, i{{32|64}} 5) +// ASAN-NEXT: call void @__asan_register_globals({{.*}}, i{{32|64}} 8) +// KASAN-NEXT: call void @__asan_register_globals({{.*}}, i{{32|64}} 7) // CHECK-NEXT: ret void // CHECK-LABEL: define internal void @asan.module_dtor // CHECK-NEXT: call void @__asan_unregister_globals // CHECK-NEXT: ret void -// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[LARGE_ARRAY:[0-9]+]], ![[ZERO_SIZE:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} // CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} // CHECK: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} // CHECK: ![[GLOBAL]] = !{{{.*}} ![[GLOBAL_LOC:[0-9]+]], !"global", i1 false, i1 false} @@ -42,12 +47,16 @@ // CHECK: ![[BLACKLISTED_GLOBAL]] = !{{{.*}}, null, null, i1 false, i1 true} // CHECK: ![[SECTIONED_GLOBAL]] = !{{{.*}} ![[SECTIONED_GLOBAL_LOC:[0-9]+]], !"sectioned_global", i1 false, i1 false} // CHECK: ![[SECTIONED_GLOBAL_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 14, i32 51} +// CHECK: ![[LARGE_ARRAY]] = !{{{.*}} ![[LARGE_ARRAY_LOC:[0-9]+]], !"large_array", i1 false, i1 false} +// CHECK: ![[LARGE_ARRAY_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 15, i32 6} +// CHECK: ![[ZERO_SIZE]] = !{{{.*}} ![[ZERO_SIZE_LOC:[0-9]+]], !"zero_size", i1 false, i1 false} +// CHECK: ![[ZERO_SIZE_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 16, i32 6} // CHECK: ![[STATIC_VAR]] = !{{{.*}} ![[STATIC_LOC:[0-9]+]], !"static_var", i1 false, i1 false} -// CHECK: ![[STATIC_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 17, i32 14} +// CHECK: ![[STATIC_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 19, i32 14} // CHECK: ![[LITERAL]] = !{{{.*}} ![[LITERAL_LOC:[0-9]+]], !"", i1 false, i1 false} -// CHECK: ![[LITERAL_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 18, i32 25} +// CHECK: ![[LITERAL_LOC]] = !{!"{{.*}}asan-globals.cpp", i32 20, i32 25} -// BLACKLIST-SRC: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} +// BLACKLIST-SRC: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[LARGE_ARRAY:[0-9]+]], ![[ZERO_SIZE:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]} // BLACKLIST-SRC: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false} // BLACKLIST-SRC: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5} // BLACKLIST-SRC: ![[GLOBAL]] = !{{{.*}} null, null, i1 false, i1 true} @@ -55,5 +64,7 @@ // BLACKLIST-SRC: ![[ATTR_GLOBAL]] = !{{{.*}}, null, null, i1 false, i1 true} // BLACKLIST-SRC: ![[BLACKLISTED_GLOBAL]] = !{{{.*}}, null, null, i1 false, i1 true} // BLACKLIST-SRC: ![[SECTIONED_GLOBAL]] = !{{{.*}} null, null, i1 false, i1 true} +// BLACKLIST-SRC: ![[LARGE_ARRAY]] = !{{{.*}} null, null, i1 false, i1 true} +// BLACKLIST-SRC: ![[ZERO_SIZE]] = !{{{.*}} null, null, i1 false, i1 true} // BLACKLIST-SRC: ![[STATIC_VAR]] = !{{{.*}} null, null, i1 false, i1 true} // BLACKLIST-SRC: ![[LITERAL]] = !{{{.*}} null, null, i1 false, i1 true} diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -796,9 +796,10 @@ StringRef getGlobalMetadataSection() const; void poisonOneInitializer(Function &GlobalInit, GlobalValue *ModuleName); void createInitializerPoisonCalls(Module &M, GlobalValue *ModuleName); - size_t MinRedzoneSizeForGlobal() const { + uint64_t getMinRedzoneSizeForGlobal() const { return RedzoneSizeForScale(Mapping.Scale); } + uint64_t getRedzoneSizeForGlobal(uint64_t SizeInBytes) const; int GetAsanVersion(const Module &M) const; const GlobalsMetadata &GlobalsMD; @@ -1807,7 +1808,7 @@ // - Need to poison all copies, not just the main thread's one. if (G->isThreadLocal()) return false; // For now, just ignore this Global if the alignment is large. - if (G->getAlignment() > MinRedzoneSizeForGlobal()) return false; + if (G->getAlignment() > getMinRedzoneSizeForGlobal()) return false; // For non-COFF targets, only instrument globals known to be defined by this // TU. @@ -2276,7 +2277,6 @@ M, M.getModuleIdentifier(), /*AllowMerging*/ false, kAsanGenPrefix); for (size_t i = 0; i < n; i++) { - static const uint64_t kMaxGlobalRedzone = 1 << 18; GlobalVariable *G = GlobalsToChange[i]; // FIXME: Metadata should be attched directly to the global directly instead @@ -2290,16 +2290,8 @@ /*AllowMerging*/ true, kAsanGenPrefix); Type *Ty = G->getValueType(); - uint64_t SizeInBytes = DL.getTypeAllocSize(Ty); - uint64_t MinRZ = MinRedzoneSizeForGlobal(); - // MinRZ <= RZ <= kMaxGlobalRedzone - // and trying to make RZ to be ~ 1/4 of SizeInBytes. - uint64_t RZ = std::max( - MinRZ, std::min(kMaxGlobalRedzone, (SizeInBytes / MinRZ / 4) * MinRZ)); - uint64_t RightRedzoneSize = RZ; - // Round up to MinRZ - if (SizeInBytes % MinRZ) RightRedzoneSize += MinRZ - (SizeInBytes % MinRZ); - assert(((RightRedzoneSize + SizeInBytes) % MinRZ) == 0); + const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty); + const uint64_t RightRedzoneSize = getRedzoneSizeForGlobal(SizeInBytes); Type *RightRedZoneTy = ArrayType::get(IRB.getInt8Ty(), RightRedzoneSize); StructType *NewTy = StructType::get(Ty, RightRedZoneTy); @@ -2315,7 +2307,7 @@ "", G, G->getThreadLocalMode()); NewGlobal->copyAttributesFrom(G); NewGlobal->setComdat(G->getComdat()); - NewGlobal->setAlignment(MaybeAlign(MinRZ)); + NewGlobal->setAlignment(MaybeAlign(getMinRedzoneSizeForGlobal())); // Don't fold globals with redzones. ODR violation detector and redzone // poisoning implicitly creates a dependence on the global's address, so it // is no longer valid for it to be marked unnamed_addr. @@ -2437,6 +2429,39 @@ return true; } +uint64_t +ModuleAddressSanitizer::getRedzoneSizeForGlobal(uint64_t SizeInBytes) const { + const uint64_t MinRZ = getMinRedzoneSizeForGlobal(); + // Limit redzone size when compiling the kernel. + const uint64_t MaxRZ = CompileKernel ? MinRZ * 2 : 1 << 18; + + // Calculate RZ, where MinRZ <= RZ <= MaxRZ, and RZ ~ 1/4 * SizeInBytes. + uint64_t RZ = + std::max(MinRZ, std::min(MaxRZ, (SizeInBytes / MinRZ / 4) * MinRZ)); + + // Round up to multiple of MinRZ. + if (SizeInBytes % MinRZ) + RZ += MinRZ - (SizeInBytes % MinRZ); + assert((RZ + SizeInBytes) % MinRZ == 0); + + if (CompileKernel && SizeInBytes && RZ % SizeInBytes) { + // When compiling the Linux kernel, ensure that the size of global+redzone + // has the same divisors as before. For certain arrays, the kernel expects + // that the global's size remains a multiple of the type's size. + // + // For example, in kernel modules certain arrays of structs shared with + // userspace are checked to be a multiple of sizeof(shared struct). These + // checks happen on the final binary. + // + // We can ensure the checks do not fail by ensuring that the array's size + // remains a multiple of the original size. + RZ += SizeInBytes - (RZ % SizeInBytes); + assert((RZ + SizeInBytes) % SizeInBytes == 0); + } + + return RZ; +} + int ModuleAddressSanitizer::GetAsanVersion(const Module &M) const { int LongSize = M.getDataLayout().getPointerSizeInBits(); bool isAndroid = Triple(M.getTargetTriple()).isAndroid();