This looks like an issue with passing structs by value. g_cclosure_marshal_VOID__PARAM is only allocating a 64 byte stack frame and is calling signal_normal via some marshalling tricks. The prototype for signal_normal includes a large struct which will be partially passed in registers and signal_normal expects to be able to write that out to the parameter save area in the callers frame.
signal_normal does end up writing out parameters to the caller stack:
And since g_cclosure_marshal_VOID__PARAM hasn't allocated enough stack we stomp all over the stack and die.
What is interesting is that signal_normal doesn't touch the struct, so why are we bothering to save it? It looks like a missing optimisation in gcc and this test case shows it:
This looks like an issue with passing structs by value. g_cclosure_ marshal_ VOID__PARAM is only allocating a 64 byte stack frame and is calling signal_normal via some marshalling tricks. The prototype for signal_normal includes a large struct which will be partially passed in registers and signal_normal expects to be able to write that out to the parameter save area in the callers frame.
signal_normal does end up writing out parameters to the caller stack:
Dump of assembler code for function signal_normal: 00c880 <+0>: lis r2,4099 00c884 <+4>: addi r2,r2,-4080 00c888 <+8>: mflr r0 00c88c <+12>: std r31,-8(r1) 00c890 <+16>: mr r31,r3 00c894 <+20>: std r0,16(r1) 00c898 <+24>: stdu r1,-48(r1) 00c89c <+28>: std r4,88(r1) 00c8a0 <+32>: std r5,96(r1) 00c8a4 <+36>: std r6,104(r1) 00c8a8 <+40>: std r7,112(r1) 00c8ac <+44>: std r8,120(r1) 00c8b0 <+48>: std r9,128(r1) 00c8b4 <+52>: std r10,136(r1)
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
0x0000000010
And since g_cclosure_ marshal_ VOID__PARAM hasn't allocated enough stack we stomp all over the stack and die.
What is interesting is that signal_normal doesn't touch the struct, so why are we bothering to save it? It looks like a missing optimisation in gcc and this test case shows it:
struct foo
{
void *a, *b, *c, *d, *e, *f, *g, *h;
#if 1
void *i;
#endif
};
int bar(struct foo foo)
{
return 0;
}
With a struct big enough to not fit into registers, we always save the whole struct out to the stack even if we never touch it:
bar:
std 3,32(1)
std 4,40(1)
li 3,0
std 5,48(1)
std 6,56(1)
std 7,64(1)
std 8,72(1)
std 9,80(1)
std 10,88(1)
blr