Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Sep 1997 10:03:05 -0400 (EDT)
From:      "Ron G. Minnich" <rminnich@Sarnoff.COM>
To:        hackers@freebsd.org
Subject:   amusing problem with varargs
Message-ID:  <Pine.SUN.3.91.970912095226.28107G-100000@terra>

next in thread | raw e-mail | index | archive | help
try the following program:

#include <stdio.h>
#include <sys/types.h>
#include <stdarg.h>
int ope9(const char *name, int flags, ...)
{
  mode_t mode;
  va_list ap;
  va_start(ap, flags);
  mode = va_arg(ap, mode_t);
  va_end(ap);
  return 1;
}
main()
{
  int f = ope9("/etc/passwd", 1, 1);
}

it will on 
FreeBSD 2.1.0-RELEASE (CLUSTER) #4: Mon Jul 29 11:10:24 EDT 1996
p0 3% ./tv
IOT trap (core dumped)
p0 4% 

And on 
FreeBSD tres.sarnoff.com 2.2.1-RELEASE FreeBSD 2.2.1-RELEASE #0: Tue Apr  
1 11:51:00 GMT 1997     
jkh@whisker.cdrom.com:/usr/src/sys/compile/GENERIC  i386
bash$ ./tv
Abort trap (core dumped)
bash$ 

(note different traps ...)

It works on:
Linux ntan.sarnoff.com 2.1.24 #54 Fri Jun 6 12:54:56 EST 1997 ppc unknown
      (note: power pc)
Linux india.sarnoff.com 2.0.30 #1 Wed Aug 13 14:03:28 EDT 1997 i486 unknown
   (cyrix)


will it fail on other freebsd's, esp. 3.x? 

The problem is in the following assertion (from stdarg.h)
#define va_arg(ap, type) \
        ((type *)(ap += sizeof(type) < sizeof(int) ? \
                (abort(), 0) : sizeof(type)))[-1]

It fails because mode_t is 16 bits. 

So, I wonder, why did linux work? They appear to use a more 
sophisticated technique, from gnu cc. 
from 
/usr/lib/gcc-lib/powerpc-unknown-linux/2.7.2.1-ppclinux/include/stdarg.h
...
/* We cast to void * and then to TYPE * because this avoids
   a warning about increasing the alignment requirement.  */

#if defined (__arm__) || defined (__i386__) || defined (__i860__) || 
defined (__ns32000__) || defined (__vax__)
/* This is for little-endian machines; small args are padded upward.  */
#define va_arg(AP, TYPE)                                                \
 (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),     \
  *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
#else /* big-endian */
/* This is for big-endian machines; small args are padded downward.  */
#define va_arg(AP, TYPE)                                                \
 (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),     \
  *((TYPE *) (void *) ((char *) (AP)                                    \
                       - ((sizeof (TYPE) < __va_rounded_size (char)     \
                           ? sizeof (TYPE) : __va_rounded_size (TYPE))))))
#endif /* big-endian */
#endif /* _STDARG_H */


FYI -- ron



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.SUN.3.91.970912095226.28107G-100000>