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]
Other format: [Raw text]

[Bug c/50581] stdarg doesn't support array types


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50581

--- Comment #3 from joseph at codesourcery dot com <joseph at codesourcery dot com> 2011-10-01 14:07:42 UTC ---
On Sat, 1 Oct 2011, Wolfgang at Solfrank dot net wrote:

> > There is no possible valid use of passing arrays to va_arg.
> 
> What makes you think so?  While the 1003.1 definition of va_arg explicitly

That the C semantics mean that:

* for C90 it is impossible to access values in the non-lvalue array passed 
(the existence of the possibility of passing an array by value to a 
variadic function in C90 is one of the most obscure and useless C 
standards corner cases there is);

* for C99, calling va_arg with such a type always results in undefined 
behavior at runtime because a pointer will have been passed rather than an 
array.

So no valid C program can ever actually access a value in this way.  Of 
course, if you tried to pass an *lvalue* array (the normal case for arrays 
in C) then it was converted to a pointer rather than passed by value, for 
both C90 and C99, and so you had undefined behavior at runtime, for both 
C90 and C99.

If you want to access a pointer, you need to pass a pointer type to 
va_arg.  This is just like accessing a promoted float or char where you 
need to specify "double" or "int".  Which is why generating an abort with 
a warning at compile time seems appropriate - it's the well-established 
practice for "char" and "float" here.  (Given the obscurity, there should 
probably be a warning for C90 as well, but without the abort.)

> > In C90, it is technically possible to use va_arg in this case without 
> > undefined behavior.  The argument passed to the function would have to be 
> > a non-lvalue array - for example, an array in a structure returned from 
> > another function.  The result of va_arg would itself be a non-lvalue 
> > array, which it is not possible to convert to a pointer, so it is not 
> > possible to access the values in the array in any way; all that can be 
> > done is to discard the value (call va_arg for its side effects) or to pass 
> > it to another variadic function.
> 
> Well, I'm not sure that I buy that.  But even then, the current implementation
> in gcc doesn't generate the correct code even only for the side effects.  The
> generated code in fact assumes that the array is passed by value, i.e. the
> pointer into the argument list (or something equivalent) is incremented by the
> size of the array instead of the size of a pointer.

Here is an example program that is valid as C90 but not as C99.  It passes 
for me with all the C90 options I tried.  That is, the caller and callee 
are consistent about the space expected to be taken by the array on the 
stack, which is all that's required since there is no way of accessing the 
array's value.  (C ABIs won't generally specify this for interoperation 
between implementations, given that passing by value an array whose value 
you can't access isn't useful and the possibility of doing so has 
disappeared in C99.)

#include <stdarg.h>

extern void abort (void);
extern void exit (int);

typedef char array[10000];
struct s { array a; } x;
void g (int a, ...);

int
main (void)
{
  g (0, (0, x).a, 1234);
  exit (0);
}

void
g (int a, ...)
{
  va_list ap;
  va_start (ap, a);
  va_arg (ap, array);
  if (va_arg (ap, int) != 1234)
    abort ();
  va_end (ap);
}

> My main use case for this feature isn't with random arrays, but with va_list
> itself.  On some architectures (AFAIK all architectures that pass some
> arguments in registers) gcc implements va_list as a one element array of some
> structure.  Without my proposed change, it isn't possible to have a va_list as
> an argument to a variadic function.  This is what my second example in the bug

Passing va_list as a function argument is generally hard, whether or not 
variadic, since you don't know whether it will be passed by reference or 
by value or what the type of the address of a va_list parameter will be.  
Portable code needs to pass a pointer to va_list or a structure containing 
va_list or use some other such means of avoiding dependence on whether 
va_list is an array.


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