Bug 18742

Summary: small struct not passed correctly as vararg
Product: gcc Reporter: Christian Lindig <lindig>
Component: targetAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: chli002, gcc-bugs, pinskia
Priority: P2 Keywords: ABI, wrong-code
Version: 4.0.0   
Target Milestone: ---   
Host: Target: powerpc-*-darwin*
Build: Known to work:
Known to fail: 3.3.2 4.0.0 Last reconfirmed: 2005-12-07 04:55:06

Description Christian Lindig 2004-11-30 17:12:05 UTC
	The following code tests that complex values are passed
        correctly. A value received by the callee is tested component by
        component to be equal with the (global) value that was passed.
        This fails for the  struct of type at2 that is passed as a var arg.

    failed in foo.c: 43
    failed in foo.c: 44

Environment:
System: Darwin jonagold.local 7.6.0 Darwin Kernel Version 7.6.0: Sun Oct 10 12:05:27 PDT 2004; root:xnu/xnu-517.9.4.obj~1/RELEASE_PPC Power Macintosh powerpc


	
host: powerpc-apple-darwin7.6.0
build: powerpc-apple-darwin7.6.0
target: powerpc-apple-darwin7.6.0
configured with: ../gcc/configure --prefix=/scratch/lindig --enable-languages=c : (reconfigured) ../gcc/configure --prefix=/scratch/lindig --enable-languages=c

How-To-Repeat:
    
    Compile and run the following code.


# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "foo.c"



# 1 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.6.0/4.0.0/include/stdarg.h" 1 3 4
# 43 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.6.0/4.0.0/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 105 "/scratch/lindig/lib/gcc/powerpc-apple-darwin7.6.0/4.0.0/include/stdarg.h" 3 4
typedef __gnuc_va_list va_list;
# 5 "foo.c" 2
extern int printf (char *, ...);

static int errors = 0;

static void failed( int line )
{ printf ("failed in %s: %d\n", "foo.c", line); errors++; }

static unsigned long int *av2 = (unsigned long int *) 361451618U;

static struct bt2 { float fv2; } kv2 = { 3984.018652 };

static
struct dt2
{ char gv2; struct ct2 { unsigned char hv2; unsigned char iv2; } jv2; }
lv2
=
    { '\x4f', { '\x27', '\x20' } };

static struct at2 { short int bv2; char cv2; } dv2 = { 14855, '\x3d' };

static double ev2 = 67318.083071;

static unsigned long int * callee_af2( struct bt2 ap2, struct dt2 bp2, ... )
{
    va_list ap;
    struct at2 mv2;
    double nv2;
    __builtin_va_start(ap,bp2);
    if (kv2.fv2 != ap2.fv2) failed (33);
    if (lv2.gv2 != bp2.gv2) failed (34);
    if (lv2.jv2.hv2 != bp2.jv2.hv2) failed (35);
    if (lv2.jv2.iv2 != bp2.jv2.iv2) failed (36);
    mv2 = __builtin_va_arg(ap,struct at2);
    nv2 = __builtin_va_arg(ap,double);
    if (mv2.bv2 != dv2.bv2) failed (39);
    if (mv2.cv2 != dv2.cv2) failed (40);
    if (nv2 != ev2) failed (41);
    __builtin_va_end(ap);
    return av2;
}

static void caller_bf2( )
{
    unsigned long int *ov2;
    ov2 = callee_af2 (kv2, lv2, dv2, ev2); if (av2 != ov2) failed (49);
}

int main( int argc, char **argv )
{ caller_bf2 (); return errors; }
Comment 1 Christian Lindig 2004-11-30 17:12:05 UTC
Fix:
	No fix known.
Comment 2 Andrew Pinski 2004-11-30 17:26:32 UTC
Confirmed.  Note also Apple's 3.3 and 3.1 also fails.  So does the FSF 3.3.2.
Comment 3 chli002@rz.uni-saarland.de 2005-01-10 15:32:23 UTC
I have found similar cases; it appears that the crucial part is a {short;char} struct or union which is 
passed as a var arg. Here is a similar program, somewhat smaller and with easier to understand names. 
Again, on MacOS X 10.3 with gcc version 3.3 20030304:

$ ./foo 
foo.c:17: failed assertion `y.f == i.f'
Abort trap

#include <stdarg.h>
#include <assert.h>
union  A { float a; double b; } c         = { 52.54 };
struct B { double d; unsigned int e; } h  = { 78.01, 834U };
union  C { short int f; char g; } i       = { 68 };
struct D { char j; double k; } n          = { 'c', 31.01 };
struct E { long long int l; double m; } o = { 167L, 17.2 };

union  A callee( struct D a, struct E b, ... )
{
    va_list ap;
    struct B x;
    union  C y;
    va_start (ap, b);
    x = va_arg (ap, struct B);
    y = va_arg (ap, union C);
    assert (y.f ==  i.f);
    va_end (ap);
    return c;
}
int main( int argc, char **arg ) { 
    union A r;
    r = callee (n, o, h, i);
    assert (c.a ==  r.a);
    return 0;
}


Comment 4 David Edelsohn 2005-01-10 15:47:07 UTC
The testcases work correctly on AIX and powerpc64-linux, so this likely is due
to Darwin not implementing consistent aggregate padding rules in GCC for
backward compatibility.
Comment 5 Iain Sandoe 2010-07-24 08:08:00 UTC
fixed at least >= 4.4