https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85894
Bug ID: 85894 Summary: PPC64LE alloca stack slot allocation allows memset to destroy the stack Product: gcc Version: 6.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: rcardoso at linux dot vnet.ibm.com Target Milestone: --- Created attachment 44172 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44172&action=edit testcase I was working on a bug in setjmp/longjmp against libc on Power (PPC64LE) https://sourceware.org/bugzilla/show_bug.cgi?id=21895 and I may find a problem with alloca. For some reason alloca is not calculating the right offset when a stack have a parameter saving area which allows a memset to destroy the caller stack frame. void foo () { int i = setjmp(jb); char *c = alloca(256); memset(c, 0, 256); lbar(i); for(;;); } So, here the caller stack frame created on <foo> function before calling setjmp: 0x00003fffb7fb0900 <foo+12>: std r0,16(r1) 0x00003fffb7fb0904 <foo+16>: std r31,-8(r1) 0x00003fffb7fb0908 <foo+20>: stdu r1,-128(r1) 0x00003fffb7fb090c <foo+24>: mr r31,r1 0x00003fffb7fb0910 <foo+28>: nop 0x00003fffb7fb0914 <foo+32>: ld r3,-32712(r2) 0x00003fffb7fb0918 <foo+36>: bl 0x3fffb7fb06a0 <00000017.plt_call._setjmp@@GLIBC_2.17> That's how the stack frame will looks like on Power: | Parameter area | <= $r1+32 +-----------------------+ | TOC (0x3fffb7fd7f00) | <= $r1+24 +-----------------------+ | LR | <= $r1+16 +-----------------------+ | CR/rsv | +-----------------------+ | foo(0x3ffffffff160) | <= $r1(sp) 0x3ffffffff0e0 <foo> +-----------------------+ | 0x3ffffffff160 | <= $r1-8 +-----------------------+ The stack pointer ($r1) is at 0x3ffffffff0e0. Now alloca is called to create a temporary space on the caller stackframe: -------------------------------------------------------- 0x00003fffb7fb0924 <+48>: stw r9,96(r31) 0x00003fffb7fb0928 <+52>: ld r9,0(r1) B+>0x00003fffb7fb092c <+56>: stdu r9,-272(r1) 0x00003fffb7fb0930 <+60>: addi r9,r1,96 -------------------------------------------------------- 0x00003fffb7fb0934 <+64>: addi r9,r9,15 0x00003fffb7fb0938 <+68>: rldicl r9,r9,60,4 0x00003fffb7fb093c <+72>: rldicr r9,r9,4,59 0x00003fffb7fb0940 <+76>: std r9,104(r31) 0x00003fffb7fb0944 <+80>: li r5,256 0x00003fffb7fb0948 <+84>: li r4,0 0x00003fffb7fb094c <+88>: ld r3,104(r31) 0x00003fffb7fb0950 <+92>: bl 0x3fffb7fb06d0 <00000017.plt_call.memset@@GLIBC_2.17> Notice, that stdu r9,-272(r1) move the stack pointer to alloca(te) the space on the stack. Now $r1 (stack pointer) is 0x3fffffffefd0 on my tests. After addi r9,r1,96 the $r9 will be 0x3ffffffff030 which marks the begin of the allocated area on the stack. The code calls memset after alloca to set those 256 bytes to zero, memset will set 16 bytes and sum 16 to the address 0x3ffffffff030 resulting in 0x3ffffffff040 and then sum this with 224 to get the end of allocated region on the stack: 0x3fffb7e6db4c <__memset_ppc+204> clrldi. r5,r5,59 0x3fffb7e6db50 <__memset_ppc+208> add r6,r6,r7 This will results on the value 0x3ffffffff120 and then it will start to set the alloca(ted) area with zeros 16 by 16 bytes: 0x3fffb7e6db60 <__memset_ppc+224> std r4,-8(r6) 0x3fffb7e6db64 <__memset_ppc+228> std r4,-16(r6) 0x3fffb7e6db68 <__memset_ppc+232> std r4,-24(r6) 0x3fffb7e6db6c <__memset_ppc+236> stdu r4,-32(r6) After the 3th iteration he will execute the code above on address 0x3ffffffff0e0 which is the caller stack frame (previous sp) and will set the 32 bits after with zeros. The caller stack frame is gone and when longjmp executes we get a Segmentation Fault at: 0x3fffb7fb0954 <foo+96> ld r2,24(r1) I don't think this is the right behavior. Notice this problem only happens when the frame needs a parameter saving area. Change lbar() to lbar(void) the code runs fine. I guess the problem with alloca is at this line: 0x00003fffb7fb092c <+56>: stdu r9,-272(r1) That offset is always -272 for a stack with or without parameters and I don't think that's correct. I've made a small test here and sum this value with the parameter offset (96): 0x00003fffb7fb092c <+56>: stdu r9,-368(r1) And it works. The code attached is the same reported on BZ#21895