jkmcnk / sx-gcc

The GNU Compiler Collection port to NEC SX CPU architecture.
GNU General Public License v2.0
0 stars 2 forks source link

the "20020412-1.c" test fails due to variable overwrite on the stack. #61

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
The "gcc.c-torture/execute/20050604-1.c" test case fails. After a deeper
investigation, I found out that the problem lies in the following code
block of the "foo" function:

    .ln 12
    ldl=    $s35,272(,$s1)
    lds $s36,280(,$s1)  #movdi case3
    mpy $s35,1,$s35
    add $s35,$s36,$s35
    ld1b    $s35,0(,$s35)
    sll $s35,$s35,24
    sra $s35,$s35,24
    and $s35,$s35,(56)0
    stl $s35,-292(,$s2)
    lds $s35,.LC3   #movdi case3
    lea $s36,1
    sts $s36,-304(,$s2)
    lea $s34,-304(,$s2)
    or  $s33,0,$s35
    bsic    $s32,($s33)

more precisely, in the "stl $s35,-292(,$s2)" instruction. This instruction
overwrites the value of the "x.a[4] = '4';" assignemnt. This later causes
the test to tail.

If I execute the "0x8000002060/2" command in the DBX debugger before the
"stl $s35,-292(,$s2)" instruction is executed for the first time, I get the
correct output:

    8000002060:  30313233 34001d40

After the "stl $s35,-292(,$s2)" instruction is executed, however the output
is, as follows:

    8000002060:  30313233 00000030

You can see that the "34" byte value was overwritten.

Original issue reported on code.google.com by nou...@gmail.com on 1 Dec 2008 at 10:56

GoogleCodeExporter commented 8 years ago
Oops, looks like I've described the error for the wrong test case. The one that 
I
actually had in mind was "gcc.c-torture/execute/20020412-1.c".

Original comment by nou...@gmail.com on 2 Dec 2008 at 10:24

GoogleCodeExporter commented 8 years ago
Below is the simplified version of the "20020412-1.c" test case:

{{{
extern void abort (void);

void foo (int size, char *t)
{
  int i;

  if (t[0] != '0')
    abort();

}

int main (void)
{
  int z = 5;
  char a[z];

  a[0] = '0';
  a[1] = '1';
  a[2] = '2';
  a[3] = '3';
  a[4] = '4';
  foo (z, a);
}

}}}

The test fails because we overwrite the "30313233 34001d40" values when putting 
the
arguments for the "foo" function to the callee stack:

    stl $s35,-284(,$s2)
    sts $s36,-280(,$s2)
    lds $s35,.LC2   #movdi case3
    lea $s36,2
    sts $s36,-296(,$s2)
    lea $s34,-296(,$s2)
    or  $s33,0,$s35
    bsic    $s32,($s33)

The values are overwritten after the "sts $s36,-296(,$s2)" instruction is 
executed.

Original comment by nou...@gmail.com on 3 Dec 2008 at 2:57

GoogleCodeExporter commented 8 years ago
Well, the error has to be in the code for dynamic allocation of arrays, since 
the
example below, which uses statically allocated array, works ok:

{{{

extern void abort (void);

void foo (int size, char *t)
{
  int i;

  if (t[0] != '0')
    abort();

}

int main (void)
{
  int z = 5;
  char a[5];

  a[0] = '0';
  a[1] = '1';
  a[2] = '2';
  a[3] = '3';
  a[4] = '4';
  foo (z, a);
}

}}}

Original comment by nou...@gmail.com on 3 Dec 2008 at 5:24

GoogleCodeExporter commented 8 years ago
After a very careful examination of the assembly code for the simplified 
example (the
one that fails), it all seems to me that the problem lies in the "lea
$s36,-272(,$s2)" instruction (see the file attached). This one loads the 
starting
address for the variable length array. But strangely, the address the "lea"
instruction loads, belongs to the stack of the callee function. Wouldn't be more
sensible that the array would be loaded to the memory space that belongs to the
caller function?

Moreover, after the stack increase, the "-272(,$s2)" address is exactly the 
address
where the arguments for the callee function are stored. As a result, the array 
gets
overwritten right before the "foo" function is being called.

Original comment by nou...@gmail.com on 4 Dec 2008 at 5:19

Attachments:

GoogleCodeExporter commented 8 years ago
It turns out that the problem was in the "STACK_DYNAMIC_OFFSET" macro which is 
used
for calculating the offset to the start of dynamically allocated memory on the 
stack
(which resulted in a "lea $s36,-272(,$s2)" instruction with the incorrect 
offset).

Before, we used the default implementation of the macro, which calculates the 
offset
to the dynamically allocated memory on the stack by using the following formula:
"STACK_DYNAMIC_OFFSET = STACK_POINTER_OFFSET + length_of_arguments". This 
formula is
valid only if the STACK_POINTER_OFFSET offset is positive. Since SX uses 
negative
STACK_POINTER_OFFSET the correct formula is, as follows:
"STACK_DYNAMIC_OFFSET = STACK_POINTER_OFFSET - length_of_arguments"

After defining the SX-specific STACK_DYNAMIC_OFFSET macro in "sx.h", the test 
case
works ok.

Original comment by nou...@gmail.com on 8 Dec 2008 at 9:35

GoogleCodeExporter commented 8 years ago
no, the definition suggested above is flawed. it makes the above test case 
work, but
only due to sheer luck.

gcc.dg/struct-by-value-22 fails due to wrong calculation of 
STACK_DYNAMIC_OFFSET.

for the time being, we assume that dynamically allocated stack space (due to 
variable
sized arrays or alloca() calls) is put between statically allocated locals and
outgoing vars. in this case the definition is 

#define STACK_DYNAMIC_OFFSET(FUNDECL)                               \
  (-SX_RSA_SIZE - current_function_outgoing_args_size - 8)

which works with all relevant test cases ...

Original comment by jmoc...@gmail.com on 6 Feb 2009 at 11:21

GoogleCodeExporter commented 8 years ago
fixed with r221.

Original comment by jmoc...@gmail.com on 6 Feb 2009 at 11:21

GoogleCodeExporter commented 8 years ago
attaching a test case that thoroughly checks for stack trashing due to dynamic 
stack
sizing.

Original comment by jmoc...@gmail.com on 6 Feb 2009 at 12:59

Attachments: