Index: include/llvm/Transforms/Utils/ASanStackFrameLayout.h =================================================================== --- include/llvm/Transforms/Utils/ASanStackFrameLayout.h +++ include/llvm/Transforms/Utils/ASanStackFrameLayout.h @@ -38,6 +38,7 @@ AllocaInst *AI; // The actual AllocaInst. size_t Offset; // Offset from the beginning of the frame; // set by ComputeASanStackFrameLayout. + unsigned Line; // Line number. }; // Output data struct for ComputeASanStackFrameLayout. Index: lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2247,7 +2247,8 @@ if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore); // Find static allocas with lifetime analysis. - DenseMap + DenseMap> AllocaToSVDMap; for (const auto &APC : StaticAllocaPoisonCallVec) { assert(APC.InsBefore); @@ -2255,22 +2256,31 @@ assert(ASan.isInterestingAlloca(*APC.AI)); assert(APC.AI->isStaticAlloca()); - AllocaToSVDMap[APC.AI] = nullptr; + auto &Pair = AllocaToSVDMap[APC.AI]; + if (const DILocation *FnLoc = EntryDebugLocation.get()) { + if (const DILocation *LifetimeLoc = APC.InsBefore->getDebugLoc().get()) { + if (LifetimeLoc->getFile() == FnLoc->getFile()) + if (unsigned Line = LifetimeLoc->getLine()) + Pair.second = std::min(Pair.second ? Pair.second : Line, Line); + } + } } SmallVector SVD; SVD.reserve(AllocaVec.size()); for (AllocaInst *AI : AllocaVec) { - size_t UseAfterScopePoisonSize = - AllocaToSVDMap.find(AI) != AllocaToSVDMap.end() - ? ASan.getAllocaSizeInBytes(*AI) - : 0; ASanStackVariableDescription D = {AI->getName().data(), ASan.getAllocaSizeInBytes(*AI), - UseAfterScopePoisonSize, + 0, AI->getAlignment(), AI, + 0, 0}; + auto It = AllocaToSVDMap.find(AI); + if (It != AllocaToSVDMap.end()) { + D.LifetimeSize = D.Size; + D.Line = It->second.second; + } SVD.push_back(D); } // Minimal header size (left redzone) is 4 pointers, @@ -2386,7 +2396,7 @@ for (const auto &Desc : SVD) { auto It = AllocaToSVDMap.find(Desc.AI); if (It != AllocaToSVDMap.end()) { - It->second = &Desc; + It->second.first = &Desc; } } @@ -2395,8 +2405,8 @@ // Poison static allocas near lifetime intrinsics. for (const auto &APC : StaticAllocaPoisonCallVec) { // Must be already set. - assert(AllocaToSVDMap[APC.AI]); - const auto &Desc = *AllocaToSVDMap[APC.AI]; + assert(AllocaToSVDMap[APC.AI].first); + const auto &Desc = *AllocaToSVDMap[APC.AI].first; assert(Desc.Offset % L.Granularity == 0); size_t Begin = Desc.Offset / L.Granularity; size_t End = Begin + (APC.Size + L.Granularity - 1) / L.Granularity; Index: lib/Transforms/Utils/ASanStackFrameLayout.cpp =================================================================== --- lib/Transforms/Utils/ASanStackFrameLayout.cpp +++ lib/Transforms/Utils/ASanStackFrameLayout.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/ASanStackFrameLayout.h" #include "llvm/ADT/SmallString.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include @@ -75,13 +76,17 @@ size_t Alignment = std::max(Granularity, Vars[i].Alignment); (void)Alignment; // Used only in asserts. size_t Size = Vars[i].Size; - const char *Name = Vars[i].Name; + std::string Name = Vars[i].Name; assert((Alignment & (Alignment - 1)) == 0); assert(Layout.FrameAlignment >= Alignment); assert((Offset % Alignment) == 0); assert(Size > 0); assert(Vars[i].LifetimeSize <= Size); - StackDescription << " " << Offset << " " << Size << " " << strlen(Name) + if (Vars[i].Line) { + Name += ":"; + Name += std::to_string(Vars[i].Line); + } + StackDescription << " " << Offset << " " << Size << " " << Name.size() << " " << Name; size_t NextAlignment = IsLast ? Granularity : std::max(Granularity, Vars[i + 1].Alignment); Index: test/Instrumentation/AddressSanitizer/stack_layout.ll =================================================================== --- test/Instrumentation/AddressSanitizer/stack_layout.ll +++ test/Instrumentation/AddressSanitizer/stack_layout.ll @@ -1,18 +1,21 @@ ; Test the ASan's stack layout. ; More tests in tests/Transforms/Utils/ASanStackFrameLayoutTest.cpp -; RUN: opt < %s -asan -asan-module -asan-stack-dynamic-alloca=0 -S \ -; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STATIC -; RUN: opt < %s -asan -asan-module -asan-stack-dynamic-alloca=1 -S \ -; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-DYNAMIC +; RUN: opt < %s -asan -asan-module -asan-stack-dynamic-alloca=0 -asan-use-after-scope -S \ +; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-STATIC +; RUN: opt < %s -asan -asan-module -asan-stack-dynamic-alloca=1 -asan-use-after-scope -S \ +; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-DYNAMIC 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" target triple = "x86_64-unknown-linux-gnu" declare void @Use(i8*) +declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind -; CHECK: private unnamed_addr constant{{.*}}3 32 10 3 XXX 64 20 3 YYY 128 30 3 ZZZ -; CHECK: private unnamed_addr constant{{.*}}3 32 5 3 AAA 64 55 3 BBB 160 555 3 CCC -; CHECK: private unnamed_addr constant{{.*}}3 256 128 3 CCC 448 128 3 BBB 608 128 3 AAA +; CHECK: private unnamed_addr constant{{.*}}3 32 10 3 XXX 64 20 3 YYY 128 30 3 ZZZ\0 +; CHECK: private unnamed_addr constant{{.*}}3 32 5 3 AAA 64 55 3 BBB 160 555 3 CCC\0 +; CHECK: private unnamed_addr constant{{.*}}3 256 128 3 CCC 448 128 3 BBB 608 128 3 AAA\0 +; CHECK: private unnamed_addr constant{{.*}}2 32 4 3 AAA 48 4 5 BBB:7\0 define void @Func1() sanitize_address { entry: @@ -77,3 +80,36 @@ store volatile i8 0, i8* %arr3.ptr ret void } + +; Check that line numbers are attached to variable names if variable +; in the same file as a function. +define void @Func5() sanitize_address #0 !dbg !11 { + %AAA = alloca i32, align 4 ; File is not the same as !11 + %BBB = alloca i32, align 4 ; File is the same as !11 + %BBB.ptr = bitcast i32* %BBB to i8* + call void @llvm.lifetime.start(i64 4, i8* nonnull %BBB.ptr), !dbg !12 + store volatile i32 5, i32* %BBB, align 4 + %AAA.ptr = bitcast i32* %AAA to i8* + call void @llvm.lifetime.start(i64 4, i8* nonnull %AAA.ptr), !dbg !14 + store volatile i32 3, i32* %AAA, align 4 + call void @llvm.lifetime.end(i64 4, i8* nonnull %AAA.ptr), !dbg !17 + call void @llvm.lifetime.end(i64 4, i8* nonnull %BBB.ptr), !dbg !18 + ret void +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1) +!1 = !DIFile(filename: "../file1.c", directory: "/") +!11 = distinct !DISubprogram(name: "Func5", scope: !1, file: !1, line: 6, unit: !0) +!12 = !DILocation(line: 7, column: 3, scope: !11) +!18 = !DILocation(line: 10, column: 1, scope: !11) + +!21 = !DIFile(filename: "../file2.c", directory: "/") +!6 = distinct !DISubprogram(name: "Func4", scope: !1, file: !21, line: 2, unit: !0) +!15 = distinct !DILocation(line: 8, column: 3, scope: !11) +!14 = !DILocation(line: 3, column: 3, scope: !6, inlinedAt: !15) +!17 = !DILocation(line: 4, column: 1, scope: !6, inlinedAt: !15) Index: unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp =================================================================== --- unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp +++ unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp @@ -37,40 +37,41 @@ SmallVector Vars = V; \ ASanStackFrameLayout L = \ ComputeASanStackFrameLayout(Vars, Granularity, MinHeaderSize); \ - EXPECT_EQ(ExpectedDescr, L.DescriptionString); \ + EXPECT_STREQ(ExpectedDescr, L.DescriptionString.c_str()); \ EXPECT_EQ(ExpectedShadow, ShadowBytesToString(GetShadowBytes(Vars, L))); \ EXPECT_EQ(ExpectedShadowAfterScope, \ ShadowBytesToString(GetShadowBytesAfterScope(Vars, L))); \ } TEST(ASanStackFrameLayout, Test) { -#define VAR(name, size, lifetime, alignment) \ +#define VAR(name, size, lifetime, alignment, line) \ ASanStackVariableDescription name##size##_##alignment = { \ #name #size "_" #alignment, \ size, \ lifetime, \ alignment, \ 0, \ - 0 \ + 0, \ + line, \ } - VAR(a, 1, 0, 1); - VAR(p, 1, 0, 32); - VAR(p, 1, 0, 256); - VAR(a, 2, 0, 1); - VAR(a, 3, 0, 1); - VAR(a, 4, 0, 1); - VAR(a, 7, 0, 1); - VAR(a, 8, 8, 1); - VAR(a, 9, 0, 1); - VAR(a, 16, 16, 1); - VAR(a, 41, 9, 1); - VAR(a, 105, 103, 1); + VAR(a, 1, 0, 1, 0); + VAR(p, 1, 0, 32, 15); + VAR(p, 1, 0, 256, 2700); + VAR(a, 2, 0, 1, 0); + VAR(a, 3, 0, 1, 0); + VAR(a, 4, 0, 1, 0); + VAR(a, 7, 0, 1, 0); + VAR(a, 8, 8, 1, 0); + VAR(a, 9, 0, 1, 0); + VAR(a, 16, 16, 1, 0); + VAR(a, 41, 9, 1, 7); + VAR(a, 105, 103, 1, 0); TEST_LAYOUT({a1_1}, 8, 16, "1 16 1 4 a1_1", "LL1R", "LL1R"); TEST_LAYOUT({a1_1}, 64, 64, "1 64 1 4 a1_1", "L1", "L1"); - TEST_LAYOUT({p1_32}, 8, 32, "1 32 1 5 p1_32", "LLLL1RRR", "LLLL1RRR"); - TEST_LAYOUT({p1_32}, 8, 64, "1 64 1 5 p1_32", "LLLLLLLL1RRRRRRR", + TEST_LAYOUT({p1_32}, 8, 32, "1 32 1 8 p1_32:15", "LLLL1RRR", "LLLL1RRR"); + TEST_LAYOUT({p1_32}, 8, 64, "1 64 1 8 p1_32:15", "LLLLLLLL1RRRRRRR", "LLLLLLLL1RRRRRRR"); TEST_LAYOUT({a1_1}, 8, 32, "1 32 1 4 a1_1", "LLLL1RRR", "LLLL1RRR"); @@ -81,24 +82,24 @@ TEST_LAYOUT({a8_1}, 8, 32, "1 32 8 4 a8_1", "LLLL0RRR", "LLLLSRRR"); TEST_LAYOUT({a9_1}, 8, 32, "1 32 9 4 a9_1", "LLLL01RR", "LLLL01RR"); TEST_LAYOUT({a16_1}, 8, 32, "1 32 16 5 a16_1", "LLLL00RR", "LLLLSSRR"); - TEST_LAYOUT({p1_256}, 8, 32, "1 256 1 6 p1_256", + TEST_LAYOUT({p1_256}, 8, 32, "1 256 1 11 p1_256:2700", "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1RRR", "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1RRR"); - TEST_LAYOUT({a41_1}, 8, 32, "1 32 41 5 a41_1", "LLLL000001RRRRRR", + TEST_LAYOUT({a41_1}, 8, 32, "1 32 41 7 a41_1:7", "LLLL000001RRRRRR", "LLLLSS0001RRRRRR"); TEST_LAYOUT({a105_1}, 8, 32, "1 32 105 6 a105_1", "LLLL00000000000001RRRRRR", "LLLLSSSSSSSSSSSSS1RRRRRR"); { SmallVector t = {a1_1, p1_256}; - TEST_LAYOUT(t, 8, 32, "2 256 1 6 p1_256 272 1 4 a1_1", + TEST_LAYOUT(t, 8, 32, "2 256 1 11 p1_256:2700 272 1 4 a1_1", "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1M1R", "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1M1R"); } { SmallVector t = {a1_1, a16_1, a41_1}; - TEST_LAYOUT(t, 8, 32, "3 32 1 4 a1_1 48 16 5 a16_1 80 41 5 a41_1", + TEST_LAYOUT(t, 8, 32, "3 32 1 4 a1_1 48 16 5 a16_1 80 41 7 a41_1:7", "LLLL1M00MM000001RRRR", "LLLL1MSSMMSS0001RRRR"); } #undef VAR