Skip to content

Commit ac6df7f

Browse files
palvesdwblaikie
authored andcommitted
llvm-dwarfdump: Don't crash if DW_AT_{decl,call}_{file,line} uses signed form
The DWARF spec says: Any debugging information entry representing the declaration of an object, module, subprogram or type may have DW_AT_decl_file, DW_AT_decl_line and DW_AT_decl_column attributes, each of whose value is an unsigned integer ^^^^^^^^ constant. If however, a producer happens to emit DW_AT_decl_file / DW_AT_decl_line using a signed integer form, llvm-dwarfdump crashes, like so: (... snip ...) 0x000000b4: DW_TAG_structure_type DW_AT_name ("test_struct") DW_AT_byte_size (136) DW_AT_decl_file (llvm-dwarfdump: (... snip ...)/llvm/include/llvm/ADT/Optional.h:197: T& llvm::optional_detail::OptionalStorage<T, true>::getValue() & [with T = long unsigned int]: Assertion `hasVal' failed. PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace. Stack dump: 0. Program arguments: /opt/rocm/llvm/bin/llvm-dwarfdump ./testsuite/outputs/gdb.rocm/lane-pc-vega20/lane-pc-vega20-kernel.so #0 0x000055cc8e78315f PrintStackTraceSignalHandler(void*) Signals.cpp:0:0 #1 0x000055cc8e780d3d SignalHandler(int) Signals.cpp:0:0 rust-lang#2 0x00007f8f2cae8420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420) rust-lang#3 0x00007f8f2c58d00b raise /build/glibc-SzIz7B/glibc-2.31/signal/../sysdeps/unix/sysv/linux/raise.c:51:1 rust-lang#4 0x00007f8f2c56c859 abort /build/glibc-SzIz7B/glibc-2.31/stdlib/abort.c:81:7 rust-lang#5 0x00007f8f2c56c729 get_sysdep_segment_value /build/glibc-SzIz7B/glibc-2.31/intl/loadmsgcat.c:509:8 rust-lang#6 0x00007f8f2c56c729 _nl_load_domain /build/glibc-SzIz7B/glibc-2.31/intl/loadmsgcat.c:970:34 rust-lang#7 0x00007f8f2c57dfd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6) rust-lang#8 0x000055cc8e58ceb9 llvm::DWARFDie::dump(llvm::raw_ostream&, unsigned int, llvm::DIDumpOptions) const (/opt/rocm/llvm/bin/llvm-dwarfdump+0x2e0eb9) rust-lang#9 0x000055cc8e58bec3 llvm::DWARFDie::dump(llvm::raw_ostream&, unsigned int, llvm::DIDumpOptions) const (/opt/rocm/llvm/bin/llvm-dwarfdump+0x2dfec3) rust-lang#10 0x000055cc8e5b28a3 llvm::DWARFCompileUnit::dump(llvm::raw_ostream&, llvm::DIDumpOptions) (.part.21) DWARFCompileUnit.cpp:0:0 Likewise with DW_AT_call_file / DW_AT_call_line. The problem is that the code in llvm/lib/DebugInfo/DWARF/DWARFDie.cpp dumping these attributes assumes that FormValue.getAsUnsignedConstant() returns an armed optional. If in debug mode, we get an assertion line the above. If in release mode, and asserts are compiled out, then we proceed as if the optional had a value, running into undefined behavior, printing whatever random value. Fix this by checking whether the optional returned by FormValue.getAsUnsignedConstant() has a value, like done in other places. In addition, DWARFVerifier.cpp is validating DW_AT_call_file / DW_AT_decl_file, but not AT_call_line / DW_AT_decl_line. This commit fixes that too. The llvm-dwarfdump/X86/verify_file_encoding.yaml testcase is extended to cover these cases. Current llvm-dwarfdump crashes running the newly-extended test. "make check-llvm-tools-llvm-dwarfdump" shows no regressions, on x86-64 GNU/Linux. Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D129392
1 parent ca50840 commit ac6df7f

File tree

3 files changed

+92
-12
lines changed

3 files changed

+92
-12
lines changed

llvm/lib/DebugInfo/DWARF/DWARFDie.cpp

+19-11
Original file line numberDiff line numberDiff line change
@@ -136,23 +136,31 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
136136
auto Color = HighlightColor::Enumerator;
137137
if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
138138
Color = HighlightColor::String;
139-
if (const auto *LT = U->getContext().getLineTableForUnit(U))
140-
if (LT->getFileNameByIndex(
141-
*FormValue.getAsUnsignedConstant(), U->getCompilationDir(),
142-
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
143-
File = '"' + File + '"';
144-
Name = File;
139+
if (const auto *LT = U->getContext().getLineTableForUnit(U)) {
140+
if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) {
141+
if (LT->getFileNameByIndex(
142+
*Val, U->getCompilationDir(),
143+
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
144+
File)) {
145+
File = '"' + File + '"';
146+
Name = File;
147+
}
145148
}
149+
}
146150
} else if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant())
147151
Name = AttributeValueString(Attr, *Val);
148152

149153
if (!Name.empty())
150154
WithColor(OS, Color) << Name;
151-
else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
152-
OS << *FormValue.getAsUnsignedConstant();
153-
else if (Attr == DW_AT_low_pc &&
154-
(FormValue.getAsAddress() ==
155-
dwarf::computeTombstoneAddress(U->getAddressByteSize()))) {
155+
else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line) {
156+
if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant()) {
157+
OS << *Val;
158+
} else {
159+
FormValue.dump(OS, DumpOpts);
160+
}
161+
} else if (Attr == DW_AT_low_pc &&
162+
(FormValue.getAsAddress() ==
163+
dwarf::computeTombstoneAddress(U->getAddressByteSize()))) {
156164
if (DumpOpts.Verbose) {
157165
FormValue.dump(OS, DumpOpts);
158166
OS << " (";

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,14 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
704704
}
705705
break;
706706
}
707+
case DW_AT_call_line:
708+
case DW_AT_decl_line: {
709+
if (!AttrValue.Value.getAsUnsignedConstant()) {
710+
ReportError("DIE has " + AttributeString(Attr) +
711+
" with invalid encoding");
712+
}
713+
break;
714+
}
707715
default:
708716
break;
709717
}

llvm/test/tools/llvm-dwarfdump/X86/verify_file_encoding.yaml

+65-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,42 @@
1414
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000100)
1515
# CHECK-NEXT: DW_AT_call_file [DW_FORM_strp] ( .debug_str[0x00000012] = "")
1616
# CHECK-NEXT: DW_AT_call_line [DW_FORM_data1] (10){{[[:space:]]}}
17+
# CHECK-NEXT: error: DIE has DW_AT_decl_file with invalid encoding{{[[:space:]]}}
18+
# CHECK-NEXT: 0x0000004a: DW_TAG_subprogram
19+
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000001b] = "foo")
20+
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000002000)
21+
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_addr] (0x0000000000003000)
22+
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_sdata] (2)
23+
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_sdata] (3)
24+
# CHECK-NEXT: DW_AT_call_file [DW_FORM_sdata] (4)
25+
# CHECK-NEXT: DW_AT_call_line [DW_FORM_sdata] (5){{[[:space:]]}}
26+
# CHECK-NEXT: error: DIE has DW_AT_decl_line with invalid encoding{{[[:space:]]}}
27+
# CHECK-NEXT: 0x0000004a: DW_TAG_subprogram
28+
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000001b] = "foo")
29+
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000002000)
30+
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_addr] (0x0000000000003000)
31+
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_sdata] (2)
32+
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_sdata] (3)
33+
# CHECK-NEXT: DW_AT_call_file [DW_FORM_sdata] (4)
34+
# CHECK-NEXT: DW_AT_call_line [DW_FORM_sdata] (5){{[[:space:]]}}
35+
# CHECK-NEXT: error: DIE has DW_AT_call_file with invalid encoding{{[[:space:]]}}
36+
# CHECK-NEXT: 0x0000004a: DW_TAG_subprogram
37+
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000001b] = "foo")
38+
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000002000)
39+
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_addr] (0x0000000000003000)
40+
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_sdata] (2)
41+
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_sdata] (3)
42+
# CHECK-NEXT: DW_AT_call_file [DW_FORM_sdata] (4)
43+
# CHECK-NEXT: DW_AT_call_line [DW_FORM_sdata] (5){{[[:space:]]}}
44+
# CHECK-NEXT: error: DIE has DW_AT_call_line with invalid encoding{{[[:space:]]}}
45+
# CHECK-NEXT: 0x0000004a: DW_TAG_subprogram
46+
# CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000001b] = "foo")
47+
# CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000002000)
48+
# CHECK-NEXT: DW_AT_high_pc [DW_FORM_addr] (0x0000000000003000)
49+
# CHECK-NEXT: DW_AT_decl_file [DW_FORM_sdata] (2)
50+
# CHECK-NEXT: DW_AT_decl_line [DW_FORM_sdata] (3)
51+
# CHECK-NEXT: DW_AT_call_file [DW_FORM_sdata] (4)
52+
# CHECK-NEXT: DW_AT_call_line [DW_FORM_sdata] (5){{[[:space:]]}}
1753

1854
--- !ELF
1955
FileHeader:
@@ -28,6 +64,7 @@ DWARF:
2864
- main
2965
- ''
3066
- inline1
67+
- foo
3168
debug_abbrev:
3269
- Table:
3370
- Code: 0x0000000000000001
@@ -68,8 +105,26 @@ DWARF:
68105
Form: DW_FORM_strp
69106
- Attribute: DW_AT_call_line
70107
Form: DW_FORM_data1
108+
- Code: 0x0000000000000004
109+
Tag: DW_TAG_subprogram
110+
Children: DW_CHILDREN_no
111+
Attributes:
112+
- Attribute: DW_AT_name
113+
Form: DW_FORM_strp
114+
- Attribute: DW_AT_low_pc
115+
Form: DW_FORM_addr
116+
- Attribute: DW_AT_high_pc
117+
Form: DW_FORM_addr
118+
- Attribute: DW_AT_decl_file
119+
Form: DW_FORM_sdata
120+
- Attribute: DW_AT_decl_line
121+
Form: DW_FORM_sdata
122+
- Attribute: DW_AT_call_file
123+
Form: DW_FORM_sdata
124+
- Attribute: DW_AT_call_line
125+
Form: DW_FORM_sdata
71126
debug_info:
72-
- Length: 0x0000000000000048
127+
- Length: 0x0000000000000061
73128
Version: 4
74129
AbbrOffset: 0x0000000000000000
75130
AddrSize: 8
@@ -93,6 +148,15 @@ DWARF:
93148
- Value: 0x0000000000000100
94149
- Value: 0x0000000000000012
95150
- Value: 0x000000000000000A
151+
- AbbrCode: 0x00000004
152+
Values:
153+
- Value: 0x000000000000001B
154+
- Value: 0x0000000000002000
155+
- Value: 0x0000000000003000
156+
- Value: 0x0000000000000002
157+
- Value: 0x0000000000000003
158+
- Value: 0x0000000000000004
159+
- Value: 0x0000000000000005
96160
- AbbrCode: 0x00000000
97161
Values: []
98162
- AbbrCode: 0x00000000

0 commit comments

Comments
 (0)