From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8861 invoked by alias); 1 Oct 2011 14:08:17 -0000 Received: (qmail 8850 invoked by uid 22791); 1 Oct 2011 14:08:16 -0000 X-SWARE-Spam-Status: No, hits=-2.9 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from localhost (HELO gcc.gnu.org) (127.0.0.1) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 01 Oct 2011 14:08:00 +0000 From: "joseph at codesourcery dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug c/50581] stdarg doesn't support array types Date: Sat, 01 Oct 2011 14:08:00 -0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: joseph at codesourcery dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated Content-Type: text/plain; charset="UTF-8" MIME-Version: 1.0 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org X-SW-Source: 2011-10/txt/msg00014.txt.bz2 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50581 --- Comment #3 from 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 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.