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.
if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore);
// Find static allocas with lifetime analysis.
- DenseMap<const AllocaInst *, const ASanStackVariableDescription *>
+ DenseMap<const AllocaInst *,
+ std::pair<const ASanStackVariableDescription *, unsigned>>
AllocaToSVDMap;
for (const auto &APC : StaticAllocaPoisonCallVec) {
assert(APC.InsBefore);
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<ASanStackVariableDescription, 16> 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,
for (const auto &Desc : SVD) {
auto It = AllocaToSVDMap.find(Desc.AI);
if (It != AllocaToSVDMap.end()) {
- It->second = &Desc;
+ It->second.first = &Desc;
}
}
// 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;
//===----------------------------------------------------------------------===//
#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 <algorithm>
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);
; 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:
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)
SmallVector<ASanStackVariableDescription, 10> 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");
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<ASanStackVariableDescription, 10> 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<ASanStackVariableDescription, 10> 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