This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
stdarg possible bug on powerpc-linux
- To: egcs-bugs at cygnus dot com
- Subject: stdarg possible bug on powerpc-linux
- From: Daniel Jacobowitz <drow at false dot org>
- Date: Tue, 9 Mar 1999 22:11:27 -0500
I am not absolutely sure that this is a legitimite problem, because I have
been unable to find a copy of the relevant pieces of the C standard. It
does work on all other platforms I have available to test on, though.
The problem is in calling one function which takes a variable number of
arguments from within another that takes a variable number of
arguments, with the inner function having more than eight arguments.
Running the attached testcase on a powerpc-linux system produces the
following:
Got 1 (0'th)
Got 2 (1'th)
Got 3 (2'th)
Got 4 (3'th)
Got 5 (4'th)
Got 6 (5'th)
Got 7 (6'th)
Got 8 (7'th)
Got 9 (8'th)
Got 10 (9'th)
Got -1
Got 9 (0'th)
Got 10 (1'th)
Got -1 (2'th)
Got 14 (3'th)
Got -1
The outer set of varargs is getting overwritten, and I suspect that other
pieces of the stack are getting clobbered. When there are exactly ten
arguments to func2:
reg = func2(8, 1, 2, 3, 4, 5, 6, 7, 8, -1);
then the problem highlighted by -DREGTEST appears; the overflow_arg_area of
the inner function overlaps the reg_save_area of the outer function.
Because there are more than eight varargs, this clobbers the outer
argument set.
Dan
/--------------------------------\ /--------------------------------\
| Daniel Jacobowitz |__| CMU, CS class of 2002 |
| Debian GNU/Linux Developer __ Part-Time Systems Programmer |
| dan@debian.org | | drow@cs.cmu.edu |
\--------------------------------/ \--------------------------------/
#include <stdarg.h>
#include <stdio.h>
#define abort()
#define REGTEST
int func1(int n, ...);
void * func2(int n, ...);
int func1(int n, ...)
{
va_list args;
void *reg;
int i, j;
va_start(args, n);
#if REGTEST
reg = func2(8, 1, 2, 3, 4, 5, 6, 7, 8, -1);
if(reg == args->reg_save_area)
abort();
#else
reg = func2(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1);
for(i = 0; i < n; i++) {
j = va_arg(args, int);
if(j != 11 + i)
abort();
printf("Got %d (%d'th)\n", j, i); fflush(stdout);
}
j = va_arg(args, int);
if(j != -1)
abort();
printf("Got %d\n", j); fflush(stdout);
#endif
va_end(args);
return 1;
}
void *func2(int n, ...)
{
va_list args;
void *reg;
int i,j;
va_start(args, n);
#if REGTEST
reg = args->overflow_arg_area;
#else
reg = 0;
for(i = 0; i < n; i++) {
j = va_arg(args, int);
if(j != 1 + i)
abort();
printf("Got %d (%d'th)\n", j, i); fflush(stdout);
}
j = va_arg(args, int);
if(j != -1)
abort();
printf("Got %d\n", j); fflush(stdout);
#endif
va_end(args);
return reg;
}
main()
{
func1(4, 11, 12, 13, 14, -1);
/* func2(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1);*/
return 0;
}