https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91347
Bug ID: 91347
Summary: [7,8,9 Regression] pointer_string in linux vsprintf.c
is miscompiled when sibling calls are optimized
Product: gcc
Version: 8.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: danglin at gcc dot gnu.org
CC: deller at gmx dot de, svens at stackframe dot org
Target Milestone: ---
Host: hppa-unknown-linux-gnu
Target: hppa-unknown-linux-gnu
Build: hppa-unknown-linux-gnu
Created attachment 46669
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46669&action=edit
Preproccessed source
Sven Schnelle wrote:
I wasn't able to write a reproducer so far, but the problem is in
lib/vsprintf.c
pointer_string():
char *pointer_string(char *buf, char *end,
const void *ptr,
struct printf_spec spec)
{
spec.base = 16;
spec.flags |= SMALL;
if (spec.field_width == -1) {
spec.field_width = 2 * sizeof(ptr);
spec.flags |= ZEROPAD;
}
return number(buf, end, (unsigned long int)ptr, spec);
}
this generates:
00003a34 <pointer_string>:
{
3a34: 4b dc 3f 91 ldw -38(sp),ret0
3a38: 6b c2 3f d9 stw rp,-14(sp)
3a3c: d3 9c 1f e8 extrw,s ret0,31,24,ret0
if (spec.field_width == -1) {
3a40: 93 80 37 ff cmpiclr,<> -1,ret0,r0
3a44: 34 1c 00 10 ldi 8,ret0
return number(buf, end, (unsigned long int)ptr, spec);
3a48: 4b d3 3f 91 ldw -38(sp),r19
3a4c: 34 17 00 00 ldi 0,r23
}
3a50: 4b c2 3f d9 ldw -14(sp),rp
return number(buf, end, (unsigned long int)ptr, spec);
3a54: d6 7c 0c 08 depw ret0,31,24,r19
3a58: 6b d3 3f 91 stw r19,-38(sp)
3a5c: e8 1e 0d bd b,l 1140 <number>,r0
3a60: 08 00 02 40 nop
3a64: 08 00 02 40 nop
I don't see where spec.base get's assigned, and even the source code line is
omitted in the objdump -S output.
The problem can be duplicated by compiling with -O2 or -Os.
The type of spec is:
struct printf_spec {
unsigned int type:8;
signed int field_width:24;
unsigned int flags:8;
unsigned int base:8;
signed int precision:16;
} __attribute__((__packed__));
Reviewing the RTL dumps, I see that the assignment of spec.base is dropped in
the dse1 pass. In vsprintf.i.258r.cse2, we have:
(insn 19 15 20 2 (set (reg:QI 113)
(const_int 16 [0x10]))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":675 65 {*pa.md:3045}
(nil))
(insn 20 19 63 2 (set (mem/j/c:QI (plus:SI (reg/f:SI 107)
(const_int 5 [0x5])) [241 spec.base+0 S1 A8])
(reg:QI 113))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":675 65 {*pa.md:3045}
(expr_list:REG_DEAD (reg:QI 113)
(expr_list:REG_DEAD (reg/f:SI 107)
(nil))))
This changes in vsprintf.i.259r.dse1 to:
(insn 19 15 21 2 (set (reg:QI 113)
(const_int 16 [0x10]))
"/home/svens/linux-kernel/parisc-linux/src/lib/vs
printf.c":675 65 {*pa.md:3045}
(nil))
(jump_insn 21 19 22 2 (set (pc)
(if_then_else (eq (reg:SI 98 [ spec$field_width ])
(const_int -1 [0xffffffffffffffff]))
(label_ref 27)
(pc)))
"/home/svens/linux-kernel/parisc-linux/src/lib/vsprintf.c":67
7 30 {*pa.md:1413}
(int_list:REG_BR_PROB 365072228 (nil))
-> 27)
The DSE processing for insn 20 is:
**scanning insn=20
mem: (plus:SI (reg/f:SI 107)
(const_int 5 [0x5]))
after canon_rtx address: (plus:SI (reg/f:SI 3 %r3)
(const_int -51 [0xffffffffffffffcd]))
gid=0 offset=-51
processing const base store gid=0[-51..-50)
mems_found = 1, cannot_delete = false
starting to process insn 20
v: 1, 2
i = -51, index = 1
deferring deletion of insn with uid = 20.
Gcc-6 doesn't drop the spec.base assignment. Dropping the assignment causes
calls to pointer_string to be output in decimal.