From arnej@mail.math.ntnu.no  Mon Jun 16 10:37:53 1997
Received: from romberg.math.ntnu.no (153@romberg.imf.unit.no [129.241.15.150])
          by hub.freebsd.org (8.8.5/8.8.5) with SMTP id KAA18088
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 16 Jun 1997 10:37:49 -0700 (PDT)
Received: (qmail 15602 invoked from network); 16 Jun 1997 17:36:21 -0000
Received: from frida.math.ntnu.no (129.241.15.136)
  by romberg.imf.unit.no with SMTP; 16 Jun 1997 17:36:21 -0000
Received: (from arnej@localhost)
          by frida.math.ntnu.no (8.8.5/8.8.4)
	  id TAA15725; Mon, 16 Jun 1997 19:36:20 +0200 (MEST)
Message-Id: <199706161736.TAA15725@frida.math.ntnu.no>
Date: Mon, 16 Jun 1997 19:36:20 +0200 (MEST)
From: arnej@mail.math.ntnu.no
Reply-To: arnej@mail.math.ntnu.no
To: FreeBSD-gnats-submit@freebsd.org
Subject: stdarg.h fails for data types < 4 bytes
X-Send-Pr-Version: 3.2

>Number:         3884
>Category:       bin
>Synopsis:       stdarg.h fails for data types < 4 bytes
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 16 10:40:01 PDT 1997
>Closed-Date:    Wed Jun 25 01:54:34 PDT 1997
>Last-Modified:  Wed Jun 25 01:58:14 PDT 1997
>Originator:     Arne Henrik Juul
>Release:        FreeBSD 2.2-STABLE i386
>Organization:
Norwegian University of Technology and Science
>Environment:

	2.2 branch and -current.

>Description:

	The standard include file <stdarg.h> #defines va_arg to
	make an explicit abort() when asked to get an argument
	with sizeof(type) < sizeof(int).  Probably stdarg.h should
	follow the conventions of the C compiler instead.

>How-To-Repeat:

	Inspect <stdarg.h>, or compile and run the following test
	program, gotten from c-torture.
#include <stdarg.h>

struct tiny
{
  short c;
};

f (int n, ...)
{
  struct tiny x;
  int i;

  va_list ap;
  va_start (ap,n);
  for (i = 0; i < n; i++)
    {
      x = va_arg (ap,struct tiny);
      if (x.c != i + 10)
        abort();
    }
  {
    long x = va_arg (ap, long);
    if (x != 123)
      abort();
  }
  va_end (ap);
}

main ()
{
  struct tiny x[3];
  x[0].c = 10;
  x[1].c = 11;
  x[2].c = 12;
  f (3, x[0], x[1], x[2], (long) 123);
  exit(0);
}

>Fix:
	Apply following patch:

--- /usr/src/sys/i386/include/stdarg.h	Wed Apr  2 14:31:20 1997
+++ ./stdarg.h	Mon Jun 16 19:16:48 1997
@@ -39,13 +39,13 @@
 
 typedef char *va_list;
 
+#define	__va_promote(type) \
+	(((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
+
 #ifdef __GNUC__
 #define va_start(AP, LASTARG) 						\
  (AP = ((va_list) __builtin_next_arg (LASTARG)))
 #else
-#define	__va_promote(type) \
-	(((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
-
 #define	va_start(ap, last) \
 	(ap = ((va_list)&(last) + __va_promote(last)))
 #endif
@@ -55,8 +55,7 @@
 	((type *)(ap += sizeof(type)))[-1]
 #else
 #define	va_arg(ap, type) \
-	((type *)(ap += sizeof(type) < sizeof(int) ? \
-		(abort(), 0) : sizeof(type)))[-1]
+	(*((type *)(ap += __va_promote(type), ap - __va_promote(type))))
 #endif
 
 #define	va_end(ap)
>Release-Note:
>Audit-Trail:

From: Bruce Evans <bde@zeta.org.au>
To: arnej@mail.math.ntnu.no, FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  Subject: Re: bin/3884: stdarg.h fails for data types < 4 bytes
Date: Tue, 17 Jun 1997 13:37:58 +1000

 >	The standard include file <stdarg.h> #defines va_arg to
 >	make an explicit abort() when asked to get an argument
 >	with sizeof(type) < sizeof(int).
 
 This is correct.  The behaviour is undefined when the type in va_arg()
 does not match its default promotion.
 
 >	Probably stdarg.h should
 >	follow the conventions of the C compiler instead.
 
 Probably not.  Generating an error is useful for detecting unportable
 code.  However, it would be better to generate the error at compile time,
 and also detect float types (which happen to have the same size as their
 default promotion on i386's) and on char and short types (which may
 happen to have the same size as their default promotion on non-i386's).
 I don't know how to do this without using a compiler builtin.
 
 >>How-To-Repeat:
 >
 >	Inspect <stdarg.h>, or compile and run the following test
 >	program, gotten from c-torture.
 
 This program does not conform to standard C.
 
 A more amusing example is the NIST POSIX Conformance Test Suite.  The
 entire test suite is non- conforming because a fundamental startup module
 uses types char, unsigned short, pid_t, clock_t, off_t and time_t in
 va_arg().  Typedef'ed types can never be used in va_arg(), because they
 may be almost anything (pid_t may be float, and time_t may be char :-).
 
 Bruce

From: "Arne Henrik Juul" <arnej@math.ntnu.no>
To: Bruce Evans <bde@zeta.org.au>, arnej@mail.math.ntnu.no,
        FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  Subject: Re: bin/3884: stdarg.h fails for data types < 4 bytes
Date: Tue, 17 Jun 1997 10:50:26 +0200

 On Jun 17, 13:37, Bruce Evans wrote:
 > Subject: Re: bin/3884: stdarg.h fails for data types < 4 bytes
 >
 > This is correct.
 
 I will argue that it is not.
 
 >  The behaviour is undefined when the type in va_arg()
 > does not match its default promotion.
 
 Correct but irrelevant.
 
 > >	Probably stdarg.h should
 > >	follow the conventions of the C compiler instead.
 >
 > Probably not.  Generating an error is useful for detecting unportable
 > code.  However, it would be better to generate the error at compile time,
 > and also detect float types (which happen to have the same size as their
 > default promotion on i386's) and on char and short types (which may
 > happen to have the same size as their default promotion on non-i386's).
 > I don't know how to do this without using a compiler builtin.
 
 We should probably ask for one, then :-)
 
 > >>How-To-Repeat:
 > >
 > >	Inspect <stdarg.h>, or compile and run the following test
 > >	program, gotten from c-torture.
 >
 > This program does not conform to standard C.
 
 If it used short, I would agree with you.  However, it uses a struct,
 and structs doesn't promote at all.  Therefore, the program is
 conforming (maybe even strictly conforming) Ansi C and must work.
 
   -  Arne H. J.

From: Bruce Evans <bde@zeta.org.au>
To: arnej@mail.math.ntnu.no, arnej@math.ntnu.no, bde@zeta.org.au,
        FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  Subject: Re: bin/3884: stdarg.h fails for data types < 4 bytes
Date: Tue, 17 Jun 1997 20:20:32 +1000

 >> >>How-To-Repeat:
 >> >
 >> >	Inspect <stdarg.h>, or compile and run the following test
 >> >	program, gotten from c-torture.
 >>
 >> This program does not conform to standard C.
 >
 >If it used short, I would agree with you.  However, it uses a struct,
 >and structs doesn't promote at all.  Therefore, the program is
 >conforming (maybe even strictly conforming) Ansi C and must work.
 
 You are right.  I should have read your example more carefully.
 
 Your patch can be improved by fixing the KERNEL case too and renaming
 __va_promote - there is no way to determine the promoted sizes without a
 builtin, and the args may have additional padding anyway, so __va_promote
 is a confusing name.  The corresponding macro is named __va_rounded_size
 in gcc/ginclude/stdarg.h and __va_size in NetBSD.
 
 Bruce

From: arnej@math.ntnu.no
To: FreeBSD-gnats-submit@FreeBSD.ORG, bde@zeta.org.au
Cc:  Subject: Re: bin/3884: stdarg.h fails for data types < 4 bytes
Date: 17 Jun 1997 12:36:01 -0000

  > Your patch can be improved by fixing the KERNEL case too and renaming
  > __va_promote - there is no way to determine the promoted sizes without a
  > builtin, and the args may have additional padding anyway, so __va_promote
  > is a confusing name.  The corresponding macro is named __va_rounded_size
  > in gcc/ginclude/stdarg.h and __va_size in NetBSD.
 
 In that case the KERNEL case becomes the same as the normal one.
 Using __va_size the result is very much like NetBSD's stdarg.h,
 the differences are:
 	NetBSD never use __builtin_next_arg; the va_start is just
 like the !__GNUC__ case below, and
 	NetBSD defines va_end(ap) to be ((void)0), probably to
 catch some possible types of bad syntax.
 
 The patch then looks like this:
 
 --- /usr/current/src/sys/i386/include/stdarg.h	Sun Feb 23 13:41:28 1997
 +++ ./stdarg.h	Tue Jun 17 13:56:27 1997
 @@ -39,25 +39,19 @@
  
  typedef char *va_list;
  
 +#define	__va_size(type) \
 +	(((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
 +
  #ifdef __GNUC__
  #define va_start(AP, LASTARG) 						\
   (AP = ((va_list) __builtin_next_arg (LASTARG)))
  #else
 -#define	__va_promote(type) \
 -	(((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
 -
  #define	va_start(ap, last) \
 -	(ap = ((va_list)&(last) + __va_promote(last)))
 +	(ap = ((va_list)&(last) + __va_size(last)))
  #endif
  
 -#ifdef KERNEL
  #define	va_arg(ap, type) \
 -	((type *)(ap += sizeof(type)))[-1]
 -#else
 -#define	va_arg(ap, type) \
 -	((type *)(ap += sizeof(type) < sizeof(int) ? \
 -		(abort(), 0) : sizeof(type)))[-1]
 -#endif
 +	(*((type *)(ap += __va_size(type), ap - __va_size(type))))
  
  #define	va_end(ap)
  
State-Changed-From-To: open->closed 
State-Changed-By: bde 
State-Changed-When: Wed Jun 25 01:54:34 PDT 1997 
State-Changed-Why:  
Fixed in -current and -2.2. 
Also fixed in varargs.h in these versions. 
I don't plan to fix it in -2.1. 
>Unformatted:
