[Bug 206810] 11.0-CURRENT/clang380-import for powerpc (32-bit): signal handlers given insufficient stack alignment

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Mon Feb 1 00:36:28 UTC 2016


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=206810

            Bug ID: 206810
           Summary: 11.0-CURRENT/clang380-import for powerpc (32-bit):
                    signal handlers given insufficient stack alignment
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: ppc
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: markmi at dsl-only.net

[syslogd, nfsd, mountd, and  make all get the described-below sorts of
segmentation faults via similar __vfprintf use during a signal handler for the
powerpc (32-bit) context identifed.]

For a system based on buildworld with TARGET_ARCH=powerpc via clang 3.8.0 (and
use of project/clang380-import -r294962) the following short program gets a
segmentation violation for the use of handler via raise:

#include <signal.h> // for signal, SIGINT, SIG_ERR, raise.
#include <stdio.h>  // for snprintf

void handler(int sig)
{
    char buf[32];
    snprintf(buf, sizeof buf, "%d", sig); // FreeBSD's world does such things
in some of its signal handlers
}

int main(void)
{
    handler(0); // works fine
    if (signal(SIGINT, handler) != SIG_ERR) raise(SIGINT); // fails during
handler
    return 0;
}

The problem actually occurs during __vfprintf (and the code it inlines),
specifically for io_flush(struct io_state *iop, locale_t locale) has:

     return (__sprint(iop->fp, &iop->uio, locale));

The code generated that calculates &iop->uio depends on alignment by masking in
the offset of 4 bytes instead of adding 4 to the address. ("li r3,4" and later
"rlwimi r23,r3,0,29,29".) With the stack misalignment via the signal delivery
the wrong address is calculated (the bit position already has a one). In fact
it calculates the same address as its does for iop->fp (fp being the first
field of *iop).

For reference:

#define NIOV 8
struct io_state {
     FILE *fp;
     struct __suio uio;      /* output information: summary */
     struct __siov iov[NIOV];/* ... and individual io vectors */
};


With the bad address propagated to

#define COPY(n)   (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))

(as p via __sfvwrite using COPY) the memcpy gets the segmentation fault.

The signal delivery is generating a modulo-4 alignment that is not aligned for
any higher power of 2. Roman Divacky reports via a list response that 16 byte
alignment is expected by llvm for ppc32. While 16 is what I expect as the ABI
requirement I do not have a definitive reference to the FreeBSD powerpc
(32-bit) ABI criteria for this (or any) context: I can not point to the
definition or a known-good secondary source to prove a violation of a rule.

But I doubt that this should be considered a clang 3.8.0 defect for ppc32: it
should be treated as a FreeBSD signal delivery defect instead as far as I can
tell.

Below I provide some gdb evidence of the good (direct handler call) vs. bad
(signal based handler call) stack alignments for handler and for __vfprintf
(and its inlined code) if you want to look. For __vfprintf's lots of local
variables (including arrays) they all end up with unusual alignments from start
from a unusual alignment.

You can stop reading this description here to avoid this detail: There is no
more after it.


(gdb) run
Starting program: /root/c_tests/a.out 

Breakpoint 10, 0x018006d4 in handler ()
(gdb) bt
#0  0x018006d4 in handler ()
#1  0x01800760 in main ()
(gdb) info frame
Stack level 0, frame at 0xffffdcb0:
pc = 0x18006d4 in handler; saved pc = 0x1800760
called by frame at 0xffffdcd0
Arglist at 0xffffdc60, args: 
Locals at 0xffffdc60, Previous frame's sp is 0xffffdcb0
Saved registers:
 r31 at 0xffffdcac, pc at 0xffffdcb4, lr at 0xffffdcb4

vs.

(gdb) cont
Continuing.

Breakpoint 10, 0x018006d4 in handler ()
(gdb) bt
#0  0x018006d4 in handler ()
#1  <signal handler called>
#2  0x00000000 in ?? ()
(gdb) info frame
Stack level 0, frame at 0xffffd73c:
pc = 0x18006d4 in handler; saved pc = 0xffffe008
called by frame at 0xffffd73c
Arglist at 0xffffd6ec, args: 
Locals at 0xffffd6ec, Previous frame's sp is 0xffffd73c
Saved registers:
 r31 at 0xffffd738, pc at 0xffffd740, lr at 0xffffd740


(gdb) info frame
Stack level 0, frame at 0xffffdad0:
pc = 0x41931590 in __vfprintf (/usr/src/lib/libc/stdio/vfprintf.c:454); saved
pc = 0x4199c644
called by frame at 0xffffdc60
source language c.
Arglist at 0xffffd880, args: fp=0xffffdb40, locale=0x419cba40
<__xlocale_global_locale>, fmt0=0x180085c "%d", ap=0xffffdc30
Locals at 0xffffd880, Previous frame's sp is 0xffffdad0
Saved registers:
. . .

vs.

(gdb) info frame
Stack level 0, frame at 0xffffd55c:
pc = 0x41931590 in __vfprintf (/usr/src/lib/libc/stdio/vfprintf.c:454); saved
pc = 0x4199c644
called by frame at 0xffffd6ec
source language c.
Arglist at 0xffffd30c, args: fp=0xffffd5cc, locale=0x419cba40
<__xlocale_global_locale>, fmt0=0x180085c "%d", ap=0xffffd6bc
Locals at 0xffffd30c, Previous frame's sp is 0xffffd55c
Saved registers:
. . .

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list