NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: port-macppc/54827: alloca() is broken in gcc 8 on powerpc
The following reply was made to PR port-macppc/54827; it has been noted by GNATS.
From: Valery Ushakov <uwe%stderr.spb.ru@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc:
Subject: Re: port-macppc/54827: alloca() is broken in gcc 8 on powerpc
Date: Fri, 3 Jan 2020 02:23:47 +0300
When gdb starts up it registers its commands. Among others:
c = add_com_alias ("save-tracepoints", "save tracepoints", class_trace, 0);
It parses "save tracepoints", finds "save", and finds its command
table. Then it needs to lookup "tracepoints" in that command table,
and that ahppens in external/gpl3/gdb/dist/gdb/cli/cli-decode.c in
lookup_cmd_1(). To perform the lookup it creates a copy of the
command:
command = (char *) alloca (len + 1);
memcpy (command, *text, len);
command[len] = '\0';
and here we have:
(gdb) p command
$68 = 0xffffe1a0 "tracepoints"
but then in the next line:
/* Look it up. */
found = 0;
the copied value in command is corrupted:
(gdb) p command
$84 = 0xffffe1a0 "tracepoi"
That alloca call is compiled to:
=> <lookup_cmd_1+152>: lwz r9,16(r31) # len
<lookup_cmd_1+156>: addi r9,r9,1
<lookup_cmd_1+160>: addi r9,r9,15
<lookup_cmd_1+164>: rlwinm r9,r9,28,4,31
<lookup_cmd_1+168>: rlwinm r9,r9,4,0,27 # len16 = round up to 16
<lookup_cmd_1+172>: lwz r10,0(r1) # r10 = back chain
<lookup_cmd_1+176>: neg r9,r9
<lookup_cmd_1+180>: stwux r10,r1,r9 # sp -= len16, store back chain
<lookup_cmd_1+184>: addi r9,r1,8 # skip back chain, LR slot
<lookup_cmd_1+188>: addi r9,r9,15
<lookup_cmd_1+192>: rlwinm r9,r9,28,4,31
<lookup_cmd_1+196>: rlwinm r9,r9,4,0,27 # round up to 16
<lookup_cmd_1+200>: stw r9,20(r31) # command = ...
and then later found = 0 is compiled to:
=> <lookup_cmd_1+252>: li r9,0
<lookup_cmd_1+256>: stw r9,8(r31) # <- overwrites!
We start with %sp = %r31 = 0xffffe1a0.
Length of "tracepoints" is 11, so alloca code pushes %sp 16 bytes,
from 0xffffe1a0 to 0xffffe190. The 8 bytes just below %sp are the
back chain and the callee's LR slot, so it skips them. Then it rounds
up the result to 16 bytes and command gets the value 0xffffe1a0. But
11 bytes starting from that address are overlapping local variables
that start at 8(%r31) (where 8 is the same offset that covers back
chain and LR slot).
Consider this minimized example, alloca-ppc.c:
void bar(char *, int *);
void
foo()
{
char *p;
int i;
p = __builtin_alloca(11);
i = 0;
bar(p, &i);
}
$ powerpc--netbsd-gcc-7.4.0 -O0 -S -o alloca-ppc-7.s alloca-ppc.c
$ powerpc--netbsd-gcc-8.3.0 -O0 -S -o alloca-ppc-8.s alloca-ppc.c
$ diff -u -I ident alloca-ppc-7.s alloca-ppc-8.s
--- alloca-ppc-7.s 2020-01-03 00:30:37.304541529 +0300
+++ alloca-ppc-8.s 2020-01-03 00:30:51.910782364 +0300
@@ -17,7 +17,7 @@
mr 31,1
.cfi_def_cfa_register 31
lwz 9,0(1)
- stwu 9,-32(1)
+ stwu 9,-16(1)
addi 9,1,8
addi 9,9,15
srwi 9,9,4
Here gcc7 correctly accounts for 8 bytes it's going to skip later and
moves %sp by roundup16(11 + 8) = 32 bytes. OTOH, gcc8 doesn't take
those 8 bytes into account and moves %sp only by roundup16(11) = 16
bytes, creating an overlap.
STARTING_FRAME_OFFSET and STACK_DYNAMIC_OFFSET in rs60000.h only got
cosmetic changes between 7 and 8 imports in our tree, it seems.
-uwe
Home |
Main Index |
Thread Index |
Old Index