Skip to content

Commit ab09f83

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 036b1e6 commit ab09f83

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
@@ -84,7 +84,17 @@ using LVTypes = SmallVector<LVType *, 8>;
8484

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

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

8999
enum class LVBinaryType { NONE, ELF, COFF };
90100
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
@@ -60,7 +60,7 @@ class LLVM_ABI LVRange final : public LVObject {
6060
LVAddress Upper = 0;
6161

6262
public:
63-
LVRange(LVAddress Address = MaxAddress)
63+
LVRange(LVAddress Address = InvalidTombstone)
6464
: LVObject(), RangesTree(Allocator), TombstoneAddress(Address),
6565
Lower(Address) {}
6666
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
@@ -156,9 +156,8 @@ class LLVM_ABI LVReader {
156156
LVAddress LowerAddress, LVAddress UpperAddress);
157157
LVRange *getSectionRanges(LVSectionIndex SectionIndex);
158158

159-
// Tombstone value. Assume 64 bits. The value is updated for each
160-
// Compile Unit that is processed.
161-
LVAddress TombstoneAddress = MaxAddress;
159+
// The value is updated for each Compile Unit that is processed.
160+
LVAddress TombstoneAddress = InvalidTombstone;
162161

163162
// Record Compilation Unit entry.
164163
void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
@@ -287,7 +286,10 @@ class LLVM_ABI LVReader {
287286
}
288287

289288
void setTombstoneAddress(LVAddress Address) { TombstoneAddress = Address; }
290-
LVAddress getTombstoneAddress() const { return TombstoneAddress; }
289+
LVAddress getTombstoneAddress() const {
290+
assert(TombstoneAddress != InvalidTombstone && "Invalid tombstone value");
291+
return TombstoneAddress;
292+
}
291293

292294
// Access to the scopes root.
293295
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)