This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

stdarg possible bug on powerpc-linux


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]