Skip to content

Commit ee72b17

Browse files
committed
Fix UB in DwarfExpression::emitLegacyZExt()
A shift-left > 63 triggers a UBSAN failure. This patch kicks the can down the road (to the consumer) by emitting a more compact representation of the shift computation in DWARF expressions. Relanding (I accidentally pushed an earlier version of the patch previously). Differential Revision: https://reviews.llvm.org/D118183
1 parent 33185e6 commit ee72b17

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,25 @@ void DwarfExpression::emitLegacySExt(unsigned FromBits) {
681681
}
682682

683683
void DwarfExpression::emitLegacyZExt(unsigned FromBits) {
684-
// (X & (1 << FromBits - 1))
685-
emitOp(dwarf::DW_OP_constu);
686-
emitUnsigned((1ULL << FromBits) - 1);
684+
// Heuristic to decide the most efficient encoding.
685+
// A ULEB can encode 7 1-bits per byte.
686+
if (FromBits / 7 < 1+1+1+1+1) {
687+
// (X & (1 << FromBits - 1))
688+
emitOp(dwarf::DW_OP_constu);
689+
emitUnsigned((1ULL << FromBits) - 1);
690+
} else {
691+
// Note that the DWARF 4 stack consists of pointer-sized elements,
692+
// so technically it doesn't make sense to shift left more than 64
693+
// bits. We leave that for the consumer to decide though. LLDB for
694+
// example uses APInt for the stack elements and can still deal
695+
// with this.
696+
emitOp(dwarf::DW_OP_lit1);
697+
emitOp(dwarf::DW_OP_constu);
698+
emitUnsigned(FromBits);
699+
emitOp(dwarf::DW_OP_shl);
700+
emitOp(dwarf::DW_OP_lit1);
701+
emitOp(dwarf::DW_OP_minus);
702+
}
687703
emitOp(dwarf::DW_OP_and);
688704
}
689705

llvm/test/DebugInfo/X86/convert-debugloc.ll

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
; RUN: | FileCheck %s --check-prefix=VERBOSE --check-prefix=CONV "--implicit-check-not={{DW_TAG|NULL}}"
2828

2929

30-
; SPLITCONV: Compile Unit:{{.*}} DWO_id = 0x62f17241069b1fa3
30+
; SPLITCONV: Compile Unit:{{.*}} DWO_id = 0x24191746f389535f
3131
; SPLIT: DW_TAG_skeleton_unit
3232

3333
; CONV: DW_TAG_compile_unit
@@ -41,6 +41,8 @@
4141
; CONV-NEXT:DW_AT_encoding {{.*}}DW_ATE_signed)
4242
; CONV-NEXT:DW_AT_byte_size {{.*}}0x04)
4343
; CONV-NOT: DW_AT
44+
; CONV: DW_TAG_base_type
45+
; CONV: DW_TAG_base_type
4446
; CONV: DW_TAG_subprogram
4547
; CONV: DW_TAG_formal_parameter
4648
; CONV: DW_TAG_variable
@@ -50,11 +52,14 @@
5052
; VERBOSE-SAME: [[SIG32]] ->
5153
; CONV-SAME: [[SIG32]]) "DW_ATE_signed_32", DW_OP_stack_value)
5254
; CONV: DW_AT_name {{.*}}"y")
55+
; CONV: DW_TAG_variable
5356
; CONV: NULL
5457
; CONV: DW_TAG_base_type
5558
; CONV: DW_AT_name {{.*}}"signed char")
5659
; CONV: DW_TAG_base_type
5760
; CONV: DW_AT_name {{.*}}"int")
61+
; CONV: DW_TAG_base_type
62+
; CONV: DW_AT_name {{.*}}"unsigned long long")
5863
; CONV: NULL
5964

6065
; NOCONV: DW_TAG_compile_unit
@@ -64,11 +69,17 @@
6469
; NOCONV: DW_AT_location (
6570
; NOCONV: {{.*}}, DW_OP_dup, DW_OP_constu 0x7, DW_OP_shr, DW_OP_lit0, DW_OP_not, DW_OP_mul, DW_OP_constu 0x8, DW_OP_shl, DW_OP_or, DW_OP_stack_value)
6671
; NOCONV: DW_AT_name ("y")
72+
; NOCONV: DW_TAG_variable
73+
; NOCONV: DW_AT_location (
74+
; NOCONV: DW_OP_constu 0x40, DW_OP_lit0, DW_OP_plus, DW_OP_lit1, DW_OP_constu 0x40, DW_OP_shl, DW_OP_lit1, DW_OP_minus, DW_OP_and, DW_OP_stack_value)
75+
; NOCONV: DW_AT_name ("z")
6776
; NOCONV: NULL
6877
; NOCONV: DW_TAG_base_type
6978
; NOCONV: DW_AT_name ("signed char")
7079
; NOCONV: DW_TAG_base_type
7180
; NOCONV: DW_AT_name ("int")
81+
; NOCONV: DW_TAG_base_type
82+
; NOCONV: DW_AT_name ("unsigned long long")
7283
; NOCONV: NULL
7384

7485

@@ -81,6 +92,7 @@ entry:
8192
;; will not attempt to eliminate. At the moment, only "convert" ops are folded.
8293
;; If you have to change the expression, the expected DWO_id also changes.
8394
call void @llvm.dbg.value(metadata i8 32, metadata !13, metadata !DIExpression(DW_OP_lit0, DW_OP_plus, DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)), !dbg !15
95+
call void @llvm.dbg.value(metadata i8 64, metadata !17, metadata !DIExpression(DW_OP_lit0, DW_OP_plus, DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 128, DW_ATE_unsigned, DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !15
8496
ret i8 %x, !dbg !16
8597
}
8698

@@ -111,3 +123,5 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
111123
!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
112124
!15 = !DILocation(line: 3, column: 14, scope: !7)
113125
!16 = !DILocation(line: 4, column: 3, scope: !7)
126+
!17 = !DILocalVariable(name: "z", scope: !7, file: !1, line: 3, type: !18)
127+
!18 = !DIBasicType(name: "unsigned long long", size: 64, encoding: DW_ATE_unsigned)

0 commit comments

Comments
 (0)