[Bug middle-end/44164] [4.5 Regression] Aliasing bug triggered by Boost.Bind/Boost.Function
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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
--- 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