The code which generates a dynamic array on the stack in the middle of a procedure (which I never would have suspected you could do in Pascal) appears to corrupt the stack in a way which makes ReturnAddress(0) either return bogus numbers or crash with a bus error. Or more accurately, assigning to sections of the created array corrupts the stack.
I don't know if this is a PowerPC only issue, or applies to other platforms as well.
This code:
program peter103;
uses GPC;
procedure Test( ParameterCount: Integer ); var i: Integer; begin WriteLn( StdErr, 'T1 ', ParameterCount, ' ', ReturnAddr2Hex(ReturnAddress (0)) ); var CProcessParameters: array [0 .. ParameterCount + 1] of CString; WriteLn( StdErr, 'T2 ', ParameterCount, ' ', Low(CProcessParameters), ' ', High(CProcessParameters), ' ', ReturnAddr2Hex(ReturnAddress (0)) ); CProcessParameters[0] := nil; for i := 1 to ParameterCount do CProcessParameters[i] := nil; WriteLn( StdErr, 'T3 ', ParameterCount, ' ', Low(CProcessParameters), ' ', High(CProcessParameters), ' ', ReturnAddr2Hex(ReturnAddress (0)) ); end;
var i: Integer; begin for i := 0 to 10 do Test( i ); end.
will either crash in the last ReturnAddress with a bus error, fail with a range check if ReturnAddress decides to return nil (because ReturnAddr2Hex range checks if passed 0 as a parameter) or return a different bogus number (different to the two previous addresses).
I discovered this as it affects Pipe in pipes.pas which is used by gp.
The code for the creation of CProcessParameters is:
lwz r2,12520(r30) addi r2,r2,1 stw r2,12448(r30) lwz r0,12448(r30) cmpwi cr7,r0,0 bge cr7,L5 bl L__p_SubrangeError$stub L5: lwz r0,12448(r30) slwi r2,r0,2 addi r2,r2,4 stw r1,12452(r30) addi r2,r2,15 addi r0,r2,15 srwi r0,r0,4 slwi r0,r0,4 lwz r2,0(r1) neg r0,r0 stwux r2,r1,r0 addi r2,r1,56 addi r0,r2,15 srwi r0,r0,4 slwi r2,r0,4 stw r2,12456(r30)
I'm afraid this taxes my PPC decoding and ABI abilities past the limits, so I can't actually tell where the problem in the code is.
Moving the definition of CProcessParameters into the variable section does not change the behaviour.
Could someone try duplicating this Linux or Windows perhaps to see if it is PPC only, or can anyone read enough PPC to figure out if the code is correct or not?
I'll keep trying to pin down exactly what is wrong...
Thanks, Peter.
The code which generates a dynamic array on the stack in the middle of a procedure (which I never would have suspected you could do in Pascal) appears to corrupt the stack in a way which makes ReturnAddress(0) either return bogus numbers or crash with a bus error. Or more accurately, assigning to sections of the created array corrupts the stack.
I think the problem is that ReturnAddress expects to find the address at 8(0(r30)) (r30 is the frame pointer I believe). But when the frame expands, r30 remains where it is while r1 (sp I think) drops down, and the return address is preserved at 0(r1), and r1 and r30 are no longer equal.
Procedure entry:
$000029e0 <_p__M0_S0_Test+0>: mflr r0 $000029e4 <_p__M0_S0_Test+4>: stmw r30,-8(r1) $000029e8 <_p__M0_S0_Test+8>: stw r0,8(r1) $000029ec <_p__M0_S0_Test+12>: stwu r1,-4240(r1) $000029f0 <_p__M0_S0_Test+16>: mr r30,r1 $000029f4 <_p__M0_S0_Test+20>: bcl- 20,4*cr7+so,$29f8 <_p__M0_S0_Test+24> $000029f8 <_p__M0_S0_Test+24>: mflr r31
r1 = r30, and 8(0(r30)) = 8(0(r1)) is the return address.
When the space is allocated on the stack for the dynamic array:
$00002a28 <_p__M0_S0_Test+72>: lwz r2,0(r1) $00002a2c <_p__M0_S0_Test+76>: neg r0,r0 $00002a30 <_p__M0_S0_Test+80>: stwux r2,r1,r0
Now r1 <> r30, and 8(0(r1)) is the return address
But ReturnAddress(0) is:
$00002a50 <_p__M0_S0_Test+112>: lwz r2,0(r30) $00002a54 <_p__M0_S0_Test+116>: lwz r0,8(r2)
Which gives a bogus result, and potentially a crash.
I'm pretty sure that's the problem, but hopefully someone with more depth of understanding of the compiler can verify it...?
Thanks, Peter.
Peter N Lewis wrote:
The code which generates a dynamic array on the stack in the middle of a procedure (which I never would have suspected you could do in Pascal) appears to corrupt the stack in a way which makes ReturnAddress(0) either return bogus numbers or crash with a bus error. Or more accurately, assigning to sections of the created array corrupts the stack.
I think the problem is that ReturnAddress expects to find the address at 8(0(r30)) (r30 is the frame pointer I believe). But when the frame expands, r30 remains where it is while r1 (sp I think) drops down, and the return address is preserved at 0(r1), and r1 and r30 are no longer equal.
Interestingly, this looks related to the infamous ppc-darwin "non-local-goto" bug http://gcc.gnu.org/ml/gcc-bugs/2003-05/msg01814.html scheduled to be fixed after the NASA puts the first humans on Mars.
Regards,
Adriaan van Os
Peter N Lewis wrote:
program peter103;
Compiling with --stack-checking reveals
warning: frame size too large for reliable stack checking warning: try reducing the number of local variables
It crashes in:
0 peter103 0x00002dc4 __darwin_gcc3_preregister_frame_info + 0x354 1 peter103 0x00002e78 _p__M0_main_program + 0x3c 2 peter103 0x00002f2c main + 0x34 3 peter103 0x00002728 start + 0x1c8 4 dyld 0x8fe1a278 _dyld_start + 0x64
the problem goes away when specify -mdynamic-no-pic (applicable for programs, not for dynamic libraries). This options generates more efficient code anyway.
Could someone try duplicating this Linux or Windows perhaps to see if it is PPC only, or can anyone read enough PPC to figure out if the code is correct or not?
Specifying -fPIC (the default on Darwin, but not on all systems).
Regards,
Adriaan van Os