Bug 20053

Summary: casting pointers to arrays in c++ produces wrong output when optimizing
Product: gcc Reporter: linuxadmin <linuxadmin>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: gcc-bugs
Priority: P3    
Version: 4.0.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:

Description linuxadmin@yandex.ru 2005-02-18 11:52:41 UTC
To: gcc-gnats@gcc.gnu.org
Subject: casting pointer to array in c++ produces wrong output when optimizing
From: linuxadmin@yandex.ru (Ivan G. Shevchenko)
Reply-To:
Cc:

>Submitter-Id:
>Originator:    Ivan G. Shevchenko
>Organization:  -
>Confidential:  no
>Synopsis:      casting pointers to arrays in c++ produces wrong output when
optimizing
>Severity:      critical
>Priority:      medium
>Category:      c++
>Class:         wrong-code
>Release:       3.4.3  AND  4.0.0 20050213 (experimental)
>Environment:
System: Linux acid 2.6.10-my #1 Fri Feb 11 12:13:56 UTC 2005 i686 athlon i386
GNU/Linux
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../gcc-sources/configure --program-suffix=snapshot
--enable-libstdcxx-debug --enable-libstdcxx-debug-flags=-w -O0 -ggdb3
>Description:
	accessing an uint32_t array (that is casted from an uint64_t pointer)
	from an overloaded operator+ leads to wrong results when optimizing
	with -O3, but produces correct results when optimizing with -O1
>How-To-Repeat:

#include<cstdlib>
#include<iostream>
using namespace std;

class TEST{
    uint64_t data_;
public:
          uint32_t& _0()     {return ((uint32_t*)&data_)[0];}
    const uint32_t& _0()const{return ((uint32_t*)&data_)[0];}
          uint32_t& _1()     {return ((uint32_t*)&data_)[1];}
    const uint32_t& _1()const{return ((uint32_t*)&data_)[1];}
/*
// same effect
          uint32_t& _0()     {return *((uint32_t*)&data_+0);}
    const uint32_t& _0()const{return *((uint32_t*)&data_+0);}
          uint32_t& _1()     {return *((uint32_t*)&data_+1);}
    const uint32_t& _1()const{return *((uint32_t*)&data_+1);}
*/
};

TEST operator+(const TEST& a,const TEST& b){
    TEST temp;
    temp._0()=a._0()+b._0(); temp._1()=a._1()+b._1();
    return temp;
}

int main(){
    TEST a,b;
    a._0()=a._1()=1;
    b._0()=b._1()=2;

    cout<<a._0()<<" "<<a._1()<<" "<<b._0()<<" "<<b._1()<<endl;

    a=a+b;
    cout<<a._0()<<" "<<a._1()<<" "<<b._0()<<" "<<b._1()<<endl;

    b=b+a;
    cout<<a._0()<<" "<<a._1()<<" "<<b._0()<<" "<<b._1()<<endl;

    return EXIT_SUCCESS;
}


Following output is produced when compiling with gcc4.
Compiling with gcc3.4.2 from MinGW and gcc3.4.3 has similar effect.
I beleave that this is a bug, because I hadn't problems with the
free intel compiler for linux with any optimizations switches.

This program should produce the following output:
(it does so with CFLAGS='-march=athlon -O1')
1 1 2 2
3 3 2 2
3 3 5 5

But with CFLAGS='-march=athlon -O3' it produces:
1 1 2 2
1 1 2 2
3 0 2 2

And with CFLAGS='-march=i486 -O3' it produces:
1 1 2 2
1 1 2 2
3 3 2 2

>Fix: no idea
Comment 1 Falk Hueffner 2005-02-18 12:38:38 UTC
This code is invalid; you're accessing an object of type uint64_t via a pointer
to uint32_t, which is not allowed. Use -fno-strict-aliasing, or use a union.
Comment 2 Andrew Pinski 2005-06-05 09:06:31 UTC
Reopening to ...
Comment 3 Andrew Pinski 2005-06-05 09:06:51 UTC
Mark as a dup of bug 21920

*** This bug has been marked as a duplicate of 21920 ***