This bug appears in ALL version of gcc that we tested since gcc 4.1.2 If you see the assembly generated by the cpp source using the -DNOT_WORKING option
you will see: main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %esi pushl %ebx pushl %ecx subl $92, %esp movl -20(%ebp), %eax movl $0, -44(%ebp) /* Here is the bug. The compiler generates code to read *location -16(%ebp) before anything was written to it! */ movl -16(%ebp), %edx leal -44(%ebp), %esi movl $0, -40(%ebp) --------------------------------------------------------- Attached are 3 files: (1) The cpp source (2) an associated assembly file needed to link. That code is not the source of the bug since the bug is in the calling procedure (3) A shell script exercising the bug and a workaround that masks the bug. This is the code that produces the bug: ------------------------------------------------------------------------------ bug.cpp File (1) ------------------------------------------------------------------------------ #include <stdio.h> #include <sys/types.h> extern "C" { extern int64_t __cmpxchg8bytes(volatile int64_t *destination, volatile int64_t exchange, volatile int64_t compare); } #if defined(WORKING) // there is no error by using the union of data class TwoPointers { public: TwoPointers() { u1.s1.First = NULL; u1.s1.Second = NULL; } void* GetFirst() const { return u1.s1.First; } void* GetSecond() const { return u1.s1.Second; } void SetFirst(void* ptr) { u1.s1.First = ptr; } void SetSecond(void* ptr) { u1.s1.Second = ptr; } union unionData { struct structData1 { void* volatile First; void* volatile Second; } s1; long long longlongData; } u1; }; __inline TwoPointers InterlockedExchange(TwoPointers* Target, TwoPointers Value) { long long retVal = __cmpxchg8bytes(( long long *)Target, *((long long *) (&Value.u1.longlongData)), *(long long *) (&Target->u1.longlongData) ) ; return ( *(TwoPointers *) &retVal ) ; } #else // defined(WORKING) // this generates wrong code class TwoPointers { public: TwoPointers() { First = NULL; Second = NULL; } void* GetFirst() const { return First; } void* GetSecond() const { return Second; } void SetFirst(void* ptr) { First = ptr; } void SetSecond(void* ptr) { Second = ptr; } void* volatile First; void* volatile Second; }; __inline TwoPointers InterlockedExchange(TwoPointers* Target, TwoPointers Value) { long long retVal = __cmpxchg8bytes(( long long *)Target, *((long long *) (&Value)), *(long long *) (&Target) ) ; return ( *(TwoPointers *) &retVal ) ; } #endif // defined(WORKING) int main() { unsigned long long i = 0xdeaddeaddeaddeadll ; unsigned long long j = 0xbeafbeafbeafbeafll ; TwoPointers a ; TwoPointers b ; a.SetFirst( (void *) 0xdeaddead ) ; a.SetSecond( ( void *) 0xdeaddead ) ; b.SetFirst( (void *) 0xbeafbeaf ) ; b.SetSecond( (void *) 0xbeafbeaf ) ; InterlockedExchange( &a, b ) ; if ( a.GetFirst() == b.GetFirst() && a.GetSecond() == b.GetSecond() ) { printf("Succeeded\n"); } else { printf("Failed\n"); printf("It should be 0x%016llx\n", *( (long long *)&b) ) ; printf("Real data is 0x%016llx\n", *( (long long *)&a) ) ; } } ------------------------------------------------------------------------- i386xadd.s File (2) ------------------------------------------------------------------------- /* BEGIN */ .global __cmpxchg8bytes .type __cmpxchg8bytes,@function __cmpxchg8bytes: pushl %ebp movl %esp, %ebp /* * stack frame layout * ============= * old (8 byes) * new (8 bytes) * ptr (4 bytes) * rip (4 bytes) * old ebp * ============ # ebp and esp point here */ /* * Save ecx, ebx CMPXCHG8B uses them. Save esi, this code uses it. */ pushl %ecx pushl %ebx pushl %esi /* move ptr to esi */ movl 8(%ebp), %esi /* move new to ecx:ebx; low order word at bottom, high word at top */ movl 16(%ebp), %ecx movl 12(%ebp), %ebx /* move old to edx:eax; low order word at bottom, high word at top */ movl 24(%ebp), %edx movl 20(%ebp), %eax /* magic word */ lock cmpxchg8b (%esi) /* restore regs and stack */ popl %esi popl %ebx popl %ecx leave ret /* END */ -------------------------------------------------------------------- File 3: runit.sh This script demonstrates the bug -------------------------------------------------------------------- #!/bin/sh program="bug" cmd_as="/usr/local/gcc-4.1.2/bin/gcc -O2 -o i386xadd.o -c i386xadd.s" echo $cmd_as $cmd_as compiler="/usr/local/gcc-4.1.2/bin/g++" for flags in NOT_WORKING WORKING do echo echo "********** Compile and run with flag $flags turned on **********" options=" -march=i686 -O3 i386xadd.o -lgcc -lgcc_s -lstdc++" cmd="$compiler $options -D$flags $program.cpp -o $program" echo $cmd $cmd echo ./$program echo done -- Summary: Incorrect code generation when compiling c++ source Product: gcc Version: 4.3.3 Status: UNCONFIRMED Severity: major Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: jacob at jacob dot remcomp dot fr http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40698