Skip to content

Commit 7df6a92

Browse files
[llvm-debuginfo-analyzer] Fix crash with WebAssembly dead code
#136772 Incorrect handling of 'tombstone' value for WebAssembly. Address comments from reviewers: - Combine test and .s file. - Introduce the concept of a meta-tombstone value, to be able to check for an invalid tombstone value.
1 parent bd7d651 commit 7df6a92

File tree

6 files changed

+88
-51
lines changed

6 files changed

+88
-51
lines changed

llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,17 @@ using LVTypes = SmallVector<LVType *, 8>;
8383

8484
using LVOffsets = SmallVector<LVOffset, 8>;
8585

86+
// The following DWARF documents detail the 'tombstone' concept:
87+
// https://dwarfstd.org/issues/231013.1.html
88+
// https://dwarfstd.org/issues/200609.1.html
89+
//
90+
// The value of the largest representable address offset (for example,
91+
// 0xffffffff when the size of an address is 32 bits).
92+
//
93+
// -1 (0xffffffff) => Valid tombstone
94+
// -2 (0xfffffffe) => Undefined tomstone
8695
const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max();
96+
const LVAddress InvalidTombstone = MaxAddress - 1;
8797

8898
enum class LVBinaryType { NONE, ELF, COFF };
8999
enum class LVComparePass { Missing, Added };

llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class LVRange final : public LVObject {
5959
LVAddress Upper = 0;
6060

6161
public:
62-
LVRange(LVAddress Address = MaxAddress)
62+
LVRange(LVAddress Address = InvalidTombstone)
6363
: LVObject(), RangesTree(Allocator), TombstoneAddress(Address),
6464
Lower(Address) {}
6565
LVRange(const LVRange &) = delete;

llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,8 @@ class LVReader {
133133
// Only for ELF format. The CodeView is handled in a different way.
134134
LVSectionIndex DotTextSectionIndex = UndefinedSectionIndex;
135135

136-
// Tombstone value. Assume 64 bits. The value is updated for each
137-
// Compile Unit that is processed.
138-
LVAddress TombstoneAddress = MaxAddress;
136+
// The value is updated for each Compile Unit that is processed.
137+
LVAddress TombstoneAddress = InvalidTombstone;
139138

140139
// Record Compilation Unit entry.
141140
void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
@@ -262,7 +261,10 @@ class LVReader {
262261
}
263262

264263
void setTombstoneAddress(LVAddress Address) { TombstoneAddress = Address; }
265-
LVAddress getTombstoneAddress() const { return TombstoneAddress; }
264+
LVAddress getTombstoneAddress() const {
265+
assert(TombstoneAddress != InvalidTombstone && "Invalid tombstone value");
266+
return TombstoneAddress;
267+
}
266268

267269
// Access to the scopes root.
268270
LVScopeRoot *getScopesRoot() const { return Root; }

llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,17 @@ class LVCodeViewReader final : public LVBinaryReader {
193193
llvm::object::COFFObjectFile &Obj, ScopedPrinter &W,
194194
StringRef ExePath)
195195
: LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF),
196-
Input(&Obj), ExePath(ExePath), LogicalVisitor(this, W, Input) {}
196+
Input(&Obj), ExePath(ExePath), LogicalVisitor(this, W, Input) {
197+
// CodeView does not have the concept of 'tombstone' address.
198+
setTombstoneAddress(MaxAddress);
199+
}
197200
LVCodeViewReader(StringRef Filename, StringRef FileFormatName,
198201
llvm::pdb::PDBFile &Pdb, ScopedPrinter &W, StringRef ExePath)
199202
: LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::COFF),
200-
Input(&Pdb), ExePath(ExePath), LogicalVisitor(this, W, Input) {}
203+
Input(&Pdb), ExePath(ExePath), LogicalVisitor(this, W, Input) {
204+
// CodeView does not have the concept of 'tombstone' address.
205+
setTombstoneAddress(MaxAddress);
206+
}
201207
LVCodeViewReader(const LVCodeViewReader &) = delete;
202208
LVCodeViewReader &operator=(const LVCodeViewReader &) = delete;
203209
~LVCodeViewReader() = default;

llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang-tombstone.s renamed to llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/wasm-crash-tombstone.s

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,66 @@
1+
# REQUIRES: x86-registered-target
2+
3+
# llvm-debuginfo-analyzer crashes on dead code
4+
# https://github.com/llvm/llvm-project/issues/136772
5+
6+
# For the attached reproducer:
7+
# llvm-dwarfdump out/lzma-lzmadec.wasm --all
8+
#
9+
# shows:
10+
#
11+
# 0x000002b3: DW_TAG_subprogram
12+
# DW_AT_low_pc (dead code)
13+
# DW_AT_high_pc (0x00000362)
14+
# DW_AT_frame_base (DW_OP_WASM_location 0x0 0x6, DW_OP_stack_value)
15+
16+
# llvm-debuginfo-analyzer out/lzma-lzmadec.wasm --print=instructions
17+
#
18+
# crashes and shows a stack dump:
19+
#
20+
# PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/
21+
# and include the crash backtrace.
22+
# Stack dump:
23+
# 0. Program arguments: llvm-debuginfo-analyzer out/lzma-lzmadec.wasm --print=instructions
24+
25+
# The test-clang-tombstone.s was produced by the following steps:
26+
# 1) clang --target=wasm32 -S -g Inputs/test-clang.cpp
27+
# -o Inputs/wasm-crash-tombstone.s
28+
# 2) Manually changing the DW_AT_low_pc for the DW_TAG_subprogram, from
29+
# .Lfunc_begin0 to 0xffffffff to mark the function as dead code:
30+
#
31+
# .int8 2 # Abbrev [2] 0x26:0x6a DW_TAG_subprogram
32+
# .int32 .Lfunc_begin0 # DW_AT_low_pc <---------
33+
# .int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
34+
35+
# .int8 2 # Abbrev [2] 0x26:0x6a DW_TAG_subprogram
36+
# .int32 0xffffffff # DW_AT_low_pc <---------
37+
# .int32 .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
38+
39+
# RUN: llvm-mc -arch=wasm32 -filetype=obj \
40+
# RUN: %p/wasm-crash-tombstone.s \
41+
# RUN: -o %t.wasm-crash-tombstone.wasm
42+
43+
# llvm-debuginfo-analyzer --select-elements=Discarde \
44+
# --print=elements \
45+
# %t.wasm-crash-tombstone.wasm 2>&1 | \
46+
# FileCheck --strict-whitespace -check-prefix=ONE %s
47+
48+
# ONE: Logical View:
49+
# ONE-NEXT: {File} '{{.*}}wasm-crash-tombstone.wasm'
50+
# ONE-EMPTY:
51+
# ONE-NEXT: {CompileUnit} 'test.cpp'
52+
# ONE-NEXT: 2 {Function} extern not_inlined 'foo' -> 'int'
53+
54+
# RUN: llvm-dwarfdump --debug-info %t.wasm-crash-tombstone.wasm | \
55+
# RUN: FileCheck %s --check-prefix=TWO
56+
57+
# TWO: DW_TAG_subprogram
58+
# TWO-NEXT: DW_AT_low_pc (dead code)
59+
# TWO-NEXT: DW_AT_high_pc
60+
# TWO-NEXT: DW_AT_frame_base
61+
# TWO-NEXT: DW_AT_linkage_name
62+
# TWO-NEXT: DW_AT_name ("foo")
63+
164
.text
265
.file "test.cpp"
366
.globaltype __stack_pointer, i32

llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/wasm-crash-tombstone.test

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)