Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 May 2001 14:34:04 +0200
From:      Cyrille Artho <cartho@silmaril.org>
To:        bugs@freebsd.org
Cc:        Ernst de Haan <ernst@jollem.com>
Subject:   Insufficient type casts in stdargs.h
Message-ID:  <3B03C53C.349F9491@silmaril.org>

next in thread | raw e-mail | index | archive | help
Hi,
in FreeBSD 4.3's stdargs.h, the macro va_arg does not contain enough
type casts. As a result, gcc 2.95.3 rejects using va_arg with void*
arguments.
The GNU stdargs.h contains extra type casts, allowing this. I rewrote
the BSD to include extra type casts, fixing now problems with void*
va_arg arguments:
Original macro in /usr/include/stdarg.h, line 53:
#define va_arg(ap, type) \
        (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))

My suggestion:
#define va_arg(ap, type) \
        (*(type *)((ap) = (type *)((char *)ap + __va_size(type)), \
	(type *)(((char *)ap) - __va_size(type))))

This adds three extra type casts, two intermediate ones to char* and one
more to type*. Moreover, I had to write out the += operator as it is not
allowed with void* anymore.
Please review this patch carefully, as it is a critical header file, and
not very easy to read - so I could have made an error, or there may be a
better way to fix the problem.

Originally, this compiler problem was discovered by Ernst de Haan, when
he tried to compile my Java program checker Jlint
(http://artho.com/jlint/). I include the full information about the line
of code that did not compile below:

Original source code:

parameter[n_parameters++] = va_arg(ap, void*);

-------------------------------------------------------------------------

Linux little endian systems:

#define va_arg(AP, TYPE)                                               
\
 (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),    
\
  *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))

Expanded source code:
parameter[n_parameters++] = ( ap  = (__gnuc_va_list) ((char *) ( ap ) +
(((sizeof (   void*  ) + sizeof (int) - 1) / sizeof (int)) * sizeof
(int)) ),       *((  void*  *) (void *) ((char *) ( ap ) - (((sizeof (  
void*  ) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) ))) ;

-------------------------------------------------------------------------

FreeBSD:

#define va_arg(ap, type) \
        (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))

Expanded source code:
parameter[n_parameters++] = (*(  void*  *)(( ap ) += (((sizeof(   void* 
) + sizeof(int) - 1) /  sizeof(int)) * sizeof(int)) , ( ap ) -
(((sizeof(   void*  ) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
))

jlint.cc:141: ANSI C++ forbids using pointer of type `void *' in
arithmetic
jlint.cc:141: ANSI C++ forbids using pointer of type `void *' in
arithmetic

Provisional fix:

#define va_arg(ap, type) \
        (*(type *)((ap) = (type *)((char *)ap + __va_size(type)), \
	(type *)(((char *)ap) - __va_size(type))))

-- 
Regards,
Cyrille Artho - http://artho.com/ - Tel. +41 - [0]1 - 632 09 88
If you go on with this nuclear arms race, all you are going to do is
make the rubble bounce.         
                -- Winston Churchill

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3B03C53C.349F9491>