Subject: standards/6923: va_start() macro can produce invalid C++ cope
To: None <gnats-bugs@gnats.netbsd.org>
From: Jaromir Dolecek <jdolecek@per4mance.cz>
List: netbsd-bugs
Date: 02/01/1999 16:06:43
>Number:         6923
>Category:       standards
>Synopsis:       va_start() macro can produce invalid C++ cope
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Feb  1 07:20:01 1999
>Last-Modified:
>Originator:     Jaromir Dolecek
>Organization:
	ICS MU, Brno, Czech Republic
>Release:        NetBSD-19981207
>Environment:
	
System: NetBSD jdolecek.per4mance.cz 1.3I NetBSD 1.3I (JDOLECEK) #0: Sun Jan 31 21:02:09 MET 1999 dolecek@jdolecek.per4mance.cz:/home/dolecek/tmp/kern-19990116/src/sys/arch/i386/compile/JDOLECEK i386


>Description:
	va_start() macro can produce code, which fail to compile
	under C++ (tested with gcc-2.7.2, egcs-1.1.1, MSVC++ 5.0),
	if parameter ``last'' contains a cast, i.e. it's called as:
		va_start(list, (const char *)foo);
	the macro get's expanded to something containing
		(va_start) &((const char *)foo) ....
	on which c++ compiler chokes
		non-lvalue in unary `&'
>How-To-Repeat:
	> cat f.cpp
	#include <stdarg.h>

	void main(int argc, ...) {
       		va_list list;
		va_start(list, (const int *)argc);
	}
	> g++ f.cpp
	f.cpp: In function `int main(...)':
	f.cpp:5: non-lvalue in unary `&'
>Fix:
	Well, I don't know what the _real_ solution would be (I am
	not a C++ fan at all), I don't even know if it's good C++ practice
	to use a cast in va_start() macro. Using gcc builtin works, though.
	It's also what other OSes do (I quickly scanned Solaris, Linux
	and FreeBSD included). Not a perfect solution, but functional one.
	Here is a patch for i386 <stdarg.h>:

--- stdarg.h.orig	Mon Feb  1 15:37:10 1999
+++ stdarg.h	Mon Feb  1 15:38:18 1999
@@ -45,8 +45,13 @@
 #define	__va_size(type) \
 	(((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
 
+#ifdef __GNUC__
+#define va_start(ap, last) \
+	((ap) = (va_list)__builtin_next_arg(last))
+#else
 #define	va_start(ap, last) \
 	((ap) = (va_list)(void *)&(last) + __va_size(last))
+#endif
 
 #define	va_arg(ap, type) \
 	(*(type *)(void *)((ap) += __va_size(type), (ap) - __va_size(type)))
	
>Audit-Trail:
>Unformatted: