Bug 30148

Summary: parameter passing bug
Product: gcc Reporter: Christian Lindig <lindig>
Component: targetAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED WONTFIX    
Severity: normal CC: fang, gcc-bugs
Priority: P3 Keywords: alias, wrong-code
Version: 4.1.1   
Target Milestone: ---   
Host: x86_64-pc-linux-gnu Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu Known to work: 4.3.0
Known to fail: 4.1.2 4.2.3 Last reconfirmed: 2008-02-04 16:16:20
Attachments: preprocessed file to reproduce the bug.

Description Christian Lindig 2006-12-11 16:55:05 UTC
The following code tests that values are passed correctly from a
call to a function. This fails, when the followign code is
compiled with -O2 and executed:

        foo: foo.c:65: callee_b0f: Assertion `b14.b3 == b20.b3' failed.

The code below is automatically generated explicitly to test for
parameter-passing bugs. Since the pre-processed code below might be
hard to understand, here is the orginal code as well.

/* These macros are defined in Lua string Quest.header, which may be
 * re-defined from the quest command line or in file quest.lua. 
 */
#ifndef QUEST_FAILED
#include <assert.h>
#define QUEST_ASSERT(x) assert(x)
#else
#define QUEST_ASSERT(x) if (!(x)) failed(__LINE__)
#endif

#include <stdarg.h>

extern int printf(char *, ...);
static int errors = 0;
static void failed(int line)
{  printf("failed in %s: %d\n", __FILE__, line); errors++; }
static union bt7 { unsigned long int b10; double *b11; } b12 = {1989374529UL};
static
    struct bt5 { unsigned int *b7; unsigned int b8; signed b9:10; } b17
        = {(unsigned int *) 229073790U, 777271108U, 408};
static union bt6 {  } b18 = {};
static union bt0 {  } b13 = {};
static
    struct bt3
    {
        float b3;
        struct bt1 { short int b0; signed b1:2; } b4;
        struct bt2 { float b2; } b5;
    }
    b14
        = {10569.23, {17187, 1}, {45076.89}};
static union bt4 { double b6; } b15 = {92314.64};
static double b16 = 89201.46;
union bt7  callee_b0f(struct bt5 bp2, union bt6 bp3, ...)
{
    va_list ap;
    typedef union bt0 bd0;
    typedef struct bt3 bd1;
    typedef union bt4 bd2;
    typedef double bd3;
    bd0 b19;
    bd1 b20;
    bd2 b21;
    bd3 b22;
    
    /* seed: 4346181125667919790 */
    va_start(ap, bp3);
    QUEST_ASSERT(b17.b7 == bp2.b7);
    QUEST_ASSERT(b17.b8 == bp2.b8);
    QUEST_ASSERT(b17.b9 == bp2.b9);
    b19 = va_arg(ap, bd0);
    b20 = va_arg(ap, bd1);
    b21 = va_arg(ap, bd2);
    b22 = va_arg(ap, bd3);
    QUEST_ASSERT(b14.b3 == b20.b3);
    QUEST_ASSERT(b14.b4.b0 == b20.b4.b0);
    QUEST_ASSERT(b14.b4.b1 == b20.b4.b1);
    QUEST_ASSERT(b14.b5.b2 == b20.b5.b2);
    QUEST_ASSERT(b15.b6 == b21.b6);
    QUEST_ASSERT(b16 == b22);
    va_end(ap);
    return b12;
}
static void caller_b1f()
{
    union bt7 b23; 
    /* seed: 4346181125667919790 */
    b23 = callee_b0f(b17, b18, b13, b14, b15, b16);
    QUEST_ASSERT(b12.b10 == b23.b10);
}
int main(int argc, char **argv) {  caller_b1f(); return errors; }

Below is the pre-processed code:        
        

# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "foo.c"
# 15 "foo.c"
# 1 "/usr/include/assert.h" 1 3 4
# 36 "/usr/include/assert.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 308 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 309 "/usr/include/features.h" 2 3 4
# 331 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 332 "/usr/include/features.h" 2 3 4
# 37 "/usr/include/assert.h" 2 3 4
# 67 "/usr/include/assert.h" 3 4



extern void __assert_fail (__const char *__assertion, __const char *__file,
      unsigned int __line, __const char *__function)
     __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));


extern void __assert_perror_fail (int __errnum, __const char *__file,
      unsigned int __line,
      __const char *__function)
     __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));




extern void __assert (const char *__assertion, const char *__file, int __line)
     __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));



# 16 "foo.c" 2





# 1 "/usr/lib/gcc/x86_64-linux-gnu/4.1.2/include/stdarg.h" 1 3 4
# 43 "/usr/lib/gcc/x86_64-linux-gnu/4.1.2/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
# 105 "/usr/lib/gcc/x86_64-linux-gnu/4.1.2/include/stdarg.h" 3 4
typedef __gnuc_va_list va_list;
# 22 "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 union bt7 { unsigned long int b10; double *b11; } b12 = {1989374529UL};
static
    struct bt5 { unsigned int *b7; unsigned int b8; signed b9:10; } b17
        = {(unsigned int *) 229073790U, 777271108U, 408};
static union bt6 { } b18 = {};
static union bt0 { } b13 = {};
static
    struct bt3
    {
        float b3;
        struct bt1 { short int b0; signed b1:2; } b4;
        struct bt2 { float b2; } b5;
    }
    b14
        = {10569.23, {17187, 1}, {45076.89}};
static union bt4 { double b6; } b15 = {92314.64};
static double b16 = 89201.46;
union bt7 callee_b0f(struct bt5 bp2, union bt6 bp3, ...)
{
    va_list ap;
    typedef union bt0 bd0;
    typedef struct bt3 bd1;
    typedef union bt4 bd2;
    typedef double bd3;
    bd0 b19;
    bd1 b20;
    bd2 b21;
    bd3 b22;


    __builtin_va_start(ap,bp3);
    ((void) ((b17.b7 == bp2.b7) ? 0 : (__assert_fail ("b17.b7 == bp2.b7", "foo.c", 58, __PRETTY_FUNCTION__), 0)));
    ((void) ((b17.b8 == bp2.b8) ? 0 : (__assert_fail ("b17.b8 == bp2.b8", "foo.c", 59, __PRETTY_FUNCTION__), 0)));
    ((void) ((b17.b9 == bp2.b9) ? 0 : (__assert_fail ("b17.b9 == bp2.b9", "foo.c", 60, __PRETTY_FUNCTION__), 0)));
    b19 = __builtin_va_arg(ap,bd0);
    b20 = __builtin_va_arg(ap,bd1);
    b21 = __builtin_va_arg(ap,bd2);
    b22 = __builtin_va_arg(ap,bd3);
    ((void) ((b14.b3 == b20.b3) ? 0 : (__assert_fail ("b14.b3 == b20.b3", "foo.c", 65, __PRETTY_FUNCTION__), 0)));
    ((void) ((b14.b4.b0 == b20.b4.b0) ? 0 : (__assert_fail ("b14.b4.b0 == b20.b4.b0", "foo.c", 66, __PRETTY_FUNCTION__), 0)));
    ((void) ((b14.b4.b1 == b20.b4.b1) ? 0 : (__assert_fail ("b14.b4.b1 == b20.b4.b1", "foo.c", 67, __PRETTY_FUNCTION__), 0)));
    ((void) ((b14.b5.b2 == b20.b5.b2) ? 0 : (__assert_fail ("b14.b5.b2 == b20.b5.b2", "foo.c", 68, __PRETTY_FUNCTION__), 0)));
    ((void) ((b15.b6 == b21.b6) ? 0 : (__assert_fail ("b15.b6 == b21.b6", "foo.c", 69, __PRETTY_FUNCTION__), 0)));
    ((void) ((b16 == b22) ? 0 : (__assert_fail ("b16 == b22", "foo.c", 70, __PRETTY_FUNCTION__), 0)));
    __builtin_va_end(ap);
    return b12;
}
static void caller_b1f()
{
    union bt7 b23;

    b23 = callee_b0f(b17, b18, b13, b14, b15, b16);
    ((void) ((b12.b10 == b23.b10) ? 0 : (__assert_fail ("b12.b10 == b23.b10", "foo.c", 79, __PRETTY_FUNCTION__), 0)));
}
int main(int argc, char **argv) { caller_b1f(); return errors; }

Environment:
System: Linux kubrick 2.6.16-2-amd64-k8-smp #1 SMP Fri Aug 18 21:10:33 CEST 2006 x86_64 GNU/Linux
Architecture: x86_64

	
host: x86_64-pc-linux-gnu
build: x86_64-pc-linux-gnu
target: x86_64-pc-linux-gnu
configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release x86_64-linux-gnu

How-To-Repeat:
	Compile the code above with -O2 and run it; this should result
        in an assertion failure.
Comment 1 Christian Lindig 2006-12-11 16:55:05 UTC
Fix:
        No fix known.
Comment 2 Christian Lindig 2006-12-13 12:09:11 UTC
Created attachment 12794 [details]
preprocessed file to reproduce the bug.

I have now attached the file that reproduces the bug to make everyone's life easier. The bug can be summarized as follows: when a struct (b14) is passed by value as a vararg, it may be garbled. In this case, the struct is passed as the second vararg (b14) where the first one (b13) is an empty struct {}. This could confuse the code that implements the calling convention.
Comment 3 Richard Biener 2008-02-04 16:16:20 UTC
Works on the trunk, fails for 4.1 and 4.2 branches with -O2, -fno-strict-aliasing
makes the failure go away there.  Inlining is not required to trigger the bug.

Probably a dup of one of the various alias-related miscompiles on the branches.
Comment 4 Steven Bosscher 2010-07-13 10:49:21 UTC
GCC 4.1 and GCC 4.2 are no longer maintained => WONTFIX.