From owner-freebsd-hackers Fri Sep 12 07:03:50 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.7/8.8.7) id HAA05172 for hackers-outgoing; Fri, 12 Sep 1997 07:03:50 -0700 (PDT) Received: from terra.Sarnoff.COM (terra.sarnoff.com [130.33.11.203]) by hub.freebsd.org (8.8.7/8.8.7) with SMTP id HAA05164 for ; Fri, 12 Sep 1997 07:03:43 -0700 (PDT) Received: (from rminnich@localhost) by terra.Sarnoff.COM (8.6.12/8.6.12) id KAA29752; Fri, 12 Sep 1997 10:03:11 -0400 Date: Fri, 12 Sep 1997 10:03:05 -0400 (EDT) From: "Ron G. Minnich" X-Sender: rminnich@terra To: hackers@freebsd.org Subject: amusing problem with varargs Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk try the following program: #include #include #include 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