Bug 20951 - bogus error passing &va_list to va_list*
Summary: bogus error passing &va_list to va_list*
Status: RESOLVED DUPLICATE of bug 14557
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 3.2.3
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-04-11 16:51 UTC by Martin Sebor
Modified: 2005-07-23 22:49 UTC (History)
1 user (show)

See Also:
Host: x86_64-redhat-linux
Target: x86_64-redhat-linux
Build: x86_64-redhat-linux
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2005-04-11 16:51:43 UTC
The program below fails to compile with gcc on EM64T. I believe the program is
well-formed based on 7.15.1.1 of C99, Footnote 212 (I am aware that footnotes
are not normative).

The second program below uses va_copy to get around the compilation error in the
first case fails to compile with the -ansi option (I am aware of gcc-specific
__builtin_va_copy). Even if the program did compile the solution seems
unreasonably complicated.

Can you confirm whether you agree that this is a conformance bug or not and if
not explain why not?

$ cat t.cpp && g++ --version && g++ -c t.cpp
#include <stdarg.h>

void foo (int, va_list*);

void bar (int i, va_list va)
{
    foo (i, &va);
}
g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-47)
Copyright (C) 2002 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

t.cpp: In function `void bar(int, __va_list_tag*)':
t.cpp:7: cannot convert `__va_list_tag**' to `__va_list_tag (*)[1]' for 
   argument `2' to `void foo(int, __va_list_tag (*)[1])'


$ cat t.cpp && g++ --version && g++ -ansi t.cpp
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>

int a [3];

int foo (int i, va_list *pva)
{
    a [i++] = va_arg (*pva, int);
    return i;
}

void bar (int i, va_list va)
{
    a [i++] = va_arg (va, int);

#ifdef va_copy
    va_list cpy;
    va_copy (cpy, va);
    va_end (va);
    i = foo (i, &cpy);
    va_copy (va, cpy);
    va_end (cpy);
#else
    i = foo (i, &va);
#endif

    a [i++] = va_arg (va, int);
}

void baz (int i, ...)
{
    va_list va;
    va_start (va, i);
    bar (i, va);
    va_end (va);
}

int main ()
{
    baz (0, 1, 2, 3);

    printf ("%d, %d, %d\n", a [0], a [1], a [2]);

    assert (1 == a [0]);
    assert (2 == a [1]);
    assert (3 == a [2]);
}
g++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-47)
Copyright (C) 2002 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

t.cpp: In function `void bar(int, __va_list_tag*)':
t.cpp:25: cannot convert `__va_list_tag**' to `__va_list_tag (*)[1]' for 
   argument `2' to `int foo(int, __va_list_tag (*)[1])'
Comment 1 Andrew Pinski 2005-04-11 17:07:07 UTC
Nope this is invalid, see PR 14557 for more discussion about this issue.
&va is equivalent to &va[0] on x86_64 since va_list is defined as an array on x86_64.

*** This bug has been marked as a duplicate of 14557 ***
Comment 2 Martin Sebor 2005-04-11 17:33:15 UTC
(In reply to comment #1)

Right. I understand why it doesn't compile and how to work around it (with gcc
at least). What I'm still not convinced of is that it's not a strict conformance
bug. The same point was raised in the discussion you pointed me to but I
couldn't find where it was addressed or if it was communicated to WG14. I.e.,
even if the requirement in C99  (that makes the test case well-formed) is
non-normative and bogus, strictly speaking this would still be a conformance bug
in the gcc implementation of va_list (after all, it is a gcc builtin, so it
seems that the compiler could do some magic whereby taking the address of a
va_list declared as an argument to a function would produce va_list* and not
va_list**).

Do you happen to know whether there's a C99 issue to fix the footnote?
Comment 3 Andrew Pinski 2005-04-11 17:35:52 UTC
(In reply to comment #2)
> Do you happen to know whether there's a C99 issue to fix the footnote?

If you read that bug's comment, you will see in comment #8:

"My recollection from last time we were discussing this is that text
above is an footnote that is not normative and in conflict with rest of
the standard, so it needs to be ignored. While I agree that this
behaviour is very unfortuante side effect of va-arg implementation,
there are some other ABIS around (PPC SysV) doing the same so the only
choice now is probably to avoid this construct."
Comment 4 Martin Sebor 2005-04-11 17:51:49 UTC
Yes, I read that comment but I still don't see anything in the standard the
footnote is in conflict with and I don't see it on the WG14 DR list(*). If the
footnote is bogus and va_list can't be universally implemented to allow programs
to initialize a va_list* with the address of a va_list function argument,it
ought to be taken out of the standard. If you are not aware of an issue against
the C standard I'll be happy to send it to the committee myself.

(*) http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm
Comment 5 joseph@codesourcery.com 2005-04-13 20:42:44 UTC
Subject: Re:  bogus error passing &va_list to va_list*

On Mon, 11 Apr 2005, sebor at roguewave dot com wrote:

> Yes, I read that comment but I still don't see anything in the standard the
> footnote is in conflict with and I don't see it on the WG14 DR list(*). If the
> footnote is bogus and va_list can't be universally implemented to allow programs
> to initialize a va_list* with the address of a va_list function argument,it
> ought to be taken out of the standard. If you are not aware of an issue against
> the C standard I'll be happy to send it to the committee myself.

I see nothing wrong with the footnote.  You can create a pointer to a 
va_list, as the footnote notes.  To do so, you need an object of type 
va_list.  Declaring a function parameter as "va_list va" doesn't declare 
such a object if va_list is an array type; it declares one of type 
"va_list_member *" where va_list is an array 
va_list_member[number_of_elements].  Just because it says you can create a 
pointer doesn't mean you can do so with "&va" if va doesn't have va_list 
type, any more that it means you can do so with "random expression I'd 
like to have va_list * type but which has nothing to do with va_list"; 
they are in exactly the same position.  If your expression has type 
va_list * according to the semantics of the language and is the address of 
a va_list object, you can use it.

(comment#1 in this bug is bogus.  &va isn't &va[0], it's the address of 
the pointer argument rather than the address of an element.  Both of these 
are of course different from the address of the va_list object itself 
which has type va_list * (i.e. va_list_member (*)[number_of_elements]) 
instead of va_list_member ** (which &va has) or va_list_member * (which 
&va[0] has).  comment#8 in bug 14557 is just confused as well; ignore it 
and read comments 10-14 instead.)

Comment 6 Martin Sebor 2005-04-13 22:06:48 UTC
(In reply to comment #5)

Thanks for the pointer. Let me try again to explain why I object to the footnote:

The footnote assumes that the reader will make the extrapolation that 1) since
va_list is an object type, and 2) since array types are (also) object types, and
3) since array types in function arguments are converted to pointers, the actual
type of a va_list object when declared as a function argument need not in fact
be va_list but va_list*, despite the fact the declaration clearly appears to say
otherwise.

I am not a casual reader of the standard -- I read and interpret standards for a
living. It seems that if I have trouble making that leap above it may not be so
obvious to others either (as demonstrated by the lively discussion in the
referenced bug).

Perhaps removing the footnote is an unnecessarily drastic change. But clarifying
it by mentioning the caveat above would, IMO, go a long way toward helping
readers avoid the trap that I (and others) fell into.