[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-18 Thread rguenth at gcc dot gnu dot org


--- Comment #11 from rguenth at gcc dot gnu dot org  2010-05-18 15:00 
---
(In reply to comment #10)
> (In reply to comment #9)
> > But the standard says in [basic.types] that "For any trivially copyable 
> > type T,
> > if two pointers to T point to distinct T objects obj1 and obj2, where 
> > neither
> > obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) 
> > making
> > up obj1 are copied into obj2,40 obj2 shall subsequently hold the same value 
> > as
> > obj1."
> 
> Yep.  But an assignment is not a byte-copy and exactly the assignment is
> what invokes the undefined behavior (not the subsequent access).
> 
> So,
> 
> struct X
> {
> char data[ sizeof( float ) ];
> };
> 
> int main()
> {
> X x1;
> new( &x1.data ) float( 3.14f );
> 
> X x2 = x1;
> 
> 
> GCC sees this as reading the float object you made live in x1.data via
> an lvalue of type X and thus decides that the float object is unused
> and removes it.

Oh, and

 "float" is a trivially copyable type. Copying X results in copying the bytes
of
 X::data (because the default copy constructor of a class does a memberwise
 copy, and the default copy constructor of an array does an elementwise copy).
 Therefore, the underlying bytes of the object of type float, initialized at
 x1.data, are copied into x2.data, which then must, if interpreted as a float,
 hold the same value as the original object.

is not what the C++ frontend does.  It emits the assignment literally:

  <) >>>
>>;

gimplified to

x2 = x1;


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-18 Thread rguenth at gcc dot gnu dot org


--- Comment #10 from rguenth at gcc dot gnu dot org  2010-05-18 14:58 
---
(In reply to comment #9)
> But the standard says in [basic.types] that "For any trivially copyable type 
> T,
> if two pointers to T point to distinct T objects obj1 and obj2, where neither
> obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making
> up obj1 are copied into obj2,40 obj2 shall subsequently hold the same value as
> obj1."

Yep.  But an assignment is not a byte-copy and exactly the assignment is
what invokes the undefined behavior (not the subsequent access).

So,

struct X
{
char data[ sizeof( float ) ];
};

int main()
{
X x1;
new( &x1.data ) float( 3.14f );

X x2 = x1;


GCC sees this as reading the float object you made live in x1.data via
an lvalue of type X and thus decides that the float object is unused
and removes it.


-- 

rguenth at gcc dot gnu dot org changed:

   What|Removed |Added

 CC||rguenth at gcc dot gnu dot
   ||org


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread pdimov at gmail dot com


--- Comment #9 from pdimov at gmail dot com  2010-05-17 20:12 ---
But the standard says in [basic.types] that "For any trivially copyable type T,
if two pointers to T point to distinct T objects obj1 and obj2, where neither
obj1 nor obj2 is a base-class subobject, if the underlying bytes (1.7) making
up obj1 are copied into obj2,40 obj2 shall subsequently hold the same value as
obj1."

"float" is a trivially copyable type. Copying X results in copying the bytes of
X::data (because the default copy constructor of a class does a memberwise
copy, and the default copy constructor of an array does an elementwise copy).
Therefore, the underlying bytes of the object of type float, initialized at
x1.data, are copied into x2.data, which then must, if interpreted as a float,
hold the same value as the original object.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread pinskia at gcc dot gnu dot org


--- Comment #8 from pinskia at gcc dot gnu dot org  2010-05-17 19:17 ---
The first example I think does as there is no way to "transfer" the dynamic
type via the struct copy.  The second one does not as the union still has a
field that is float and it is only unspecified behavior if you access the other
field in the union (IIRC).


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread pdimov at gmail dot com


--- Comment #7 from pdimov at gmail dot com  2010-05-17 19:10 ---
(In reply to comment #6)
> Basically the middle-end sees this the same as
>   int i = 1, j;
>   float *p = new (&i) float(0.0);
>   j = i;
>   return *reinterpret_cast(&j);
> and you expect to return 0.0.

The int/float example does violate the aliasing rules, but I don't think that
it properly describes what's happening.

I see it more like a combination of the following two examples:

#include 

struct X
{
char data[ sizeof( float ) ];
};

int main()
{
X x1;
new( &x1.data ) float( 3.14f );

X x2 = x1;

std::cout << *(float const*)&x2.data << std::endl;
}

and

#include 

union Y
{
int i;
float f;
};

int main()
{
Y y1;
y1.f = 3.14f;

Y y2 = y1;

std::cout << y2.f << std::endl;
}

I don't think either of them violates the standard.


-- 

pdimov at gmail dot com changed:

   What|Removed |Added

 CC||pdimov at gmail dot com


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread rguenth at gcc dot gnu dot org


--- Comment #6 from rguenth at gcc dot gnu dot org  2010-05-17 15:57 ---
Basically the middle-end sees this the same as

  int i = 1, j;
  float *p = new (&i) float(0.0);
  j = i;
  return *reinterpret_cast(&j);

and you expect to return 0.0.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread rguenth at gcc dot gnu dot org


--- Comment #5 from rguenth at gcc dot gnu dot org  2010-05-17 15:50 ---
(In reply to comment #4)
> (In reply to comment #3)
> > The boost folks may be able to tell if they at any place copy a
> > function_buffer object via the assignment operator.
> 
> It seems so. From Peter Dimov :
> 
> > [...] after stepping through the code, it turns out that function_buffer is
> > indeed assigned directly, due to the fact that __has_trivial_copy and
> > __has_trivial_destructor report true for the stored function object.

Which means that it is either a C++ frontend bug not protecting this
aggregate assignment properly or a bug in Boost as the functor type stored
to function_buffer is not a member of the union.  The functor types
are for example seen in

const functor_type* in_functor =
  reinterpret_cast(&in_buffer.data);
new ((void*)&out_buffer.data) functor_type(*in_functor);

but functor_type (a template param) is not a member of said union.

People were arguing that the char member in the union should make this
valid, but nothing in the C++ frontend communicates that to the
alias analysis stage.  People also were arguing only a character
array member would qualify, possibly covering the whole union in size.

A workaround for boost can be constructed following the fix for PR42832.
Due to an unrelated bug using memcpy for the assingment won't work.


-- 

rguenth at gcc dot gnu dot org changed:

   What|Removed |Added

 Status|WAITING |NEW
   Last reconfirmed|2010-05-17 09:39:31 |2010-05-17 15:50:41
   date||


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread maxime at altribe dot org


--- Comment #4 from maxime at altribe dot org  2010-05-17 13:10 ---
(In reply to comment #3)
> The boost folks may be able to tell if they at any place copy a
> function_buffer object via the assignment operator.

It seems so. From Peter Dimov :

> [...] after stepping through the code, it turns out that function_buffer is
> indeed assigned directly, due to the fact that __has_trivial_copy and
> __has_trivial_destructor report true for the stored function object.


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread rguenth at gcc dot gnu dot org


--- Comment #3 from rguenth at gcc dot gnu dot org  2010-05-17 09:44 ---
The boost folks may be able to tell if they at any place copy a
function_buffer object via the assignment operator.

I see they also have funny stuff like get_vtable() and are playing with
typeinfos.


-- 

rguenth at gcc dot gnu dot org changed:

   What|Removed |Added

 Status|NEW |WAITING


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164



[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function

2010-05-17 Thread rguenth at gcc dot gnu dot org


--- Comment #2 from rguenth at gcc dot gnu dot org  2010-05-17 09:39 ---
It's not a dup of PR42834 (but it might be the same issue as PR42832 which
was a libstdc++ bug or a frontend bug).

It happens to work on trunk, so it might also be a dup of PR43987 (though
unlikely), rather different inlining might have made the bug latent.

I can confirm the observed effect.  I didn't investigate on whether this
is a bug in boost or not (we're changing our minds on what is valid and
what not all the time anyway).


-- 

rguenth at gcc dot gnu dot org changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
 Ever Confirmed|0   |1
  Known to fail||4.5.0
  Known to work||4.4.3 4.6.0
   Last reconfirmed|-00-00 00:00:00 |2010-05-17 09:39:31
   date||
Summary|[4.5.0] Aliasing bug|[4.5 Regression] Aliasing
   |triggered by|bug triggered by
   |Boost.Bind/Boost.Function   |Boost.Bind/Boost.Function
   Target Milestone|--- |4.5.1


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44164