[root@localhost gcc_err]# g++ -Wall -c -O3 test.cpp test.cpp: In member function 'void test::bar(std::_List_iterator<KeyPairPtr<int, int> >&)': test.cpp:14: warning: dereferencing pointer '__x.13' does break strict-aliasing rules /usr/local/gcc_current/lib/gcc/i686-pc-linux-gnu/4.4.0/include/c++/bits/stl_tree.h:530: note: initialized from here test.cpp:14: warning: dereferencing pointer '__x.13' does break strict-aliasing rules /usr/local/gcc_current/lib/gcc/i686-pc-linux-gnu/4.4.0/include/c++/bits/stl_tree.h:530: note: initialized from here [root@localhost gcc_err]# g++ -v Using built-in specs. Target: i686-pc-linux-gnu Configured with: ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion : (reconfigured) ../gcc_current/configure --prefix=/usr/local/gcc_current --enable-shared --enable-threads=posix --enable-checking=release --enable-__cxa_atexit --enable-version-specific-runtime-libs --enable-languages=c,c++ --no-create --no-recursion Thread model: posix gcc version 4.4.0 20081210 (experimental) [trunk revision 142645] (GCC) [root@localhost gcc_err]# uname -a Linux localhost.localdomain 2.6.26.6-49.fc8 #1 SMP Fri Oct 17 15:59:36 EDT 2008 i686 i686 i386 GNU/Linux [root@localhost gcc_err]# cat test.cpp #include <set> #include <list> template<class Key, class Info> class KeyPairPtr { public: typedef typename std::pair< const Key, Info > Pair; Pair *pair_ptr; }; template<class Key, class Info> bool operator <( const KeyPairPtr<Key, Info> &left, const KeyPairPtr<Key, Info> &right ) { return left.pair_ptr < right.pair_ptr; } typedef KeyPairPtr<int,int> key_val; class test { test(); void bar( std::list<key_val>::iterator &ci ); std::set<key_val> foo; }; void test::bar( std::list<key_val>::iterator &ci ) { test ctx; ctx.foo.insert( *ci ); }
Note that the reason the diagnostic happens is either a bug in libstdc++ or the points-to solver or the TBAA pruning in the points-to solver. In the end we access the object 'ctx' via a pointer of type const struct _Rb_tree_node *. So the question is if anywhere in 'ctx' there is such a struct. It seems to access the _M_t._M_impl._M_header field which is a _Rb_tree_node_base but I cannot see a _Rb_tree_node object in it. Instead _Rb_tree_node is derived from _Rb_tree_node_base and adds a _M_value_field. But accessing this via this path in struct _Rb_tree_impl : public _Node_allocator { _Key_compare _M_key_compare; _Rb_tree_node_base _M_header; size_type _M_node_count; certainly violates aliasing rules. I do not see what _Rb_tree_impl::_S_value wants to access. There seems to be nothing there?
The relevant path through the CFG is struct test ctx; <bb 2>: # ctx_108 = VDEF <ctx_103(D)> # SMT.120_109 = VDEF <SMT.120_104(D)> # SMT.121_110 = VDEF <SMT.121_105(D)> # SMT.122_111 = VDEF <SMT.122_106(D)> # SMT.123_112 = VDEF <SMT.123_107(D)> __comp_ctor (&ctx); # VUSE <SMT.121_110> D.10437_5 = ci_1(D)->_M_node; D.10438_6 = (struct _List_node *) D.10437_5; # VUSE <ctx_108> D.10494_9 = ctx.foo._M_t._M_impl._M_header._M_parent; __y_10 = (struct _Rb_tree_node *) D.10494_9; __y_12 = (struct _Rb_tree_node *) &ctx.foo._M_t._M_impl._M_header; ... <bb 7>: # __y_21 = PHI <__y_56(6), __y_12(2)> ... <bb 21>: D.10504_36 = &__y_21->D.9518; ... ... <bb 23>: __x.13_77 = (const struct _Rb_tree_node *) D.10504_36; # VUSE <SMT.123_100> D.11044_78 = D.10438_6->_M_data.pair_ptr; # VUSE <SMT.122_96> D.11045_79 = __x.13_77->_M_value_field.pair_ptr; (it's not clear to me what &__y_21->D.9518 accesses - this seems to be a magic, anonymous thing. The constraints tell me its at offset zero though.)
Can you explain in better detail which aliasing issues you are seeing in _Rb_tree_impl (per Comment #1)? At line 530 I cannot see anything obviously wrong: a pointer to the base is casted to the derived type (just a static cast) and then _M_value_field of the latter is accessed.
The access is ((const struct _Rb_tree_node *) &ctx.foo._M_t._M_impl._M_header.D.9518)->_M_value_field.pair_ptr but _M_header is of type _Rb_tree_node_base (and is embedded in _M_impl). _Rb_tree_node_base does not have a _M_value_field member, so I do not see that the memory that is accessed is really "there". This "D.9518" thing may somehow magically cover for it (but it's at offset zero of _M_header), but certainly TBAA isn't aware that this is a legal access. Of course I lack complete understanding of how the implementation details of the rb tree are supposed to work. So, if this is not a libstdc++ problem then it is a C++ FE problem.
Sorry, but I still do not understand: __x (a const _Rb_tree_node_base *) is casted to _Const_Link_type (a const _Rb_tree_node<_Val> *) before the access, then of course an _M_value_field esists. By the way, all these cast games are very, very old (I hope we are not uncovering one more aliasing issue in the HP/SGI code)...
But there is no space for _Rb_tree_node<_Val> in ctx.foo._M_t._M_impl. struct _Rb_tree_impl : public _Node_allocator { _Key_compare _M_key_compare; _Rb_tree_node_base _M_header; size_type _M_node_count; the _M_header member is of type _Rb_tree_node_base, so I don't see how you can cast that to _Rb_tree_node<_Val> and expect the _M_value_field to magically appear in memory. At least this is what the alias analysis code complains about and thus says this access accesses nothing (legally). Now you can of course tell me that .D.9518 makes the difference, but this difference is not communicated to the middle-end properly by the C++ frontend.
(In reply to comment #6) > But there is no space for _Rb_tree_node<_Val> in ctx.foo._M_t._M_impl. > > struct _Rb_tree_impl : public _Node_allocator > { > _Key_compare _M_key_compare; > _Rb_tree_node_base _M_header; > size_type _M_node_count; This has nothing to do with the allocated nodes. > > the _M_header member is of type _Rb_tree_node_base, so I don't see how you > can cast that to _Rb_tree_node<_Val> and expect the _M_value_field to magically > appear in memory. Hey Richard, don't tell me it's the first time you see production code casting a pointer from base to derived and accessing a member existing only in the derived type. Indeed, the HP / SGI STL people did that, not the worse programmers in the world ;) Anyway, if you think this is something wrong from the aliasing specifications point of view, please point me to the relevant sections of the Standard, let's work this out, is going to be painful and risky, I'm afraid...
Heh, of course not - I have been doing this myself gazillions of times. I am just looking at this from the middle-end perspective where the middle-end appears to see an _object_ ctx with a specific member layout. If you then access this with a different layout then you are doomed. I have to dig into the trees coming from the FE in this case, but now I'm leaving for a 2+ week vacation w/o internet access, so ... this has to wait.
Btw, if you want to dig yourself - the problem is that the alias set of const struct _Rb_tree_node is not a subset of struct test. So the access of any part of an object of type struct test through a pointer of type const struct _Rb_tree_node * invokes undefined behavior (from the middle-end perspective). See alias.c:record_component_aliases for how the relationship is built.
Hey y'all, if this isn't a libstdc++ issue can it be re-categorized to the gcc component?
I'm not sure it isn't.
This isn't really a warning from system headers: test.cpp:14: warning: dereferencing pointer '__x.13' does break strict-aliasing rules the location for the dereference is in test.cpp (if that is correct or not is another issue). There is at least a bug that we will emit the note: part even if the warning was suppressed - I am going to fix that. I can omit the warning for pointers that are declared in system headers in addition to that. Probably this is what is the better behavior - but I cannot easily report the dereference location even if it is in a system header but the pointer is _not_ from a system header -- which is probably what would be wanted here. So, t.h: #pragma GCC system_header inline float deref_float (float *p) { return *p; } t.C: #include "t.h" float transform(int i) { return deref_float ((float *)&i); } _should_ emit a warning? Even if it looks like t.h: In function 'float transform(int)': t.h:3: warning: dereferencing pointer 'i.0' does break strict-aliasing rules t.C:5: note: initialized from here ? IMHO we want to warn unless _both_, the declaration and the dereference is in a system header.
(In reply to comment #12) > This isn't really a warning from system headers: > > test.cpp:14: warning: dereferencing pointer '__x.13' does break strict-aliasing > rules > > the location for the dereference is in test.cpp (if that is correct or not > is another issue). There is at least a bug that we will emit the note: part > even if the warning was suppressed - I am going to fix that. > > I can omit the warning for pointers that are declared in system headers > in addition to that. Probably this is what is the better behavior - but > I cannot easily report the dereference location even if it is in a system > header but the pointer is _not_ from a system header -- which is probably > what would be wanted here. > > So, > > t.h: > #pragma GCC system_header > > inline float deref_float (float *p) { return *p; } > > t.C: > #include "t.h" > > float transform(int i) > { > return deref_float ((float *)&i); > } > > _should_ emit a warning? Even if it looks like > > t.h: In function 'float transform(int)': > t.h:3: warning: dereferencing pointer 'i.0' does break strict-aliasing rules > t.C:5: note: initialized from here > > ? > > IMHO we want to warn unless _both_, the declaration and the dereference is > in a system header. > this will be painfull for users, e.g. boost::optional uses so called aligned_storage via mistic void*/casts/etc and now i'm getting these warnings from boost-system-headers. in this way, the -isystem switch is completely useless.
Ok, how about -Wstrict-aliasing=3 warning only if both the dereference and the declaration are not from system-headers (this is then the default for -Wall) and with -Wstrict-aliasing=2 (or =1) warn if either of them is not from system-headers?
Smaller testcase for the possible libstdc++ / C++ FE issue, build with -O2 -finline-functions -Wstrict-aliasing -Wsystem-headers #include <set> class test { test(); void bar(int ci); std::set<int> foo; }; void test::bar(int ci ) { test ctx; ctx.foo.insert( ci ); } /usr/include/c++/4.4/bits/stl_function.h: In member function ‘void test::bar(int)’: /usr/include/c++/4.4/bits/stl_function.h:230: warning: dereferencing pointer ‘__x.13’ does break strict-aliasing rules /usr/include/c++/4.4/bits/stl_tree.h:530: note: initialized from here /usr/include/c++/4.4/bits/stl_function.h:230: warning: dereferencing pointer ‘__x.13’ does break strict-aliasing rules /usr/include/c++/4.4/bits/stl_tree.h:530: note: initialized from here I am now trying to investigate who is at fault.
There is only a conditional path through the program that violates aliasing rules, likely never executed. We do not detect this fact because of a points-to solver issue, PR38826.
Subject: Bug 38477 Author: rguenth Date: Wed Jan 14 16:45:22 2009 New Revision: 143374 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=143374 Log: 2009-01-14 Richard Guenther <rguenther@suse.de> PR tree-optimization/38826 PR middle-end/38477 * tree-ssa-structalias.c (emit_alias_warning): Emit the pointer initialization notes only if we actually emitted a warning. (intra_create_variable_infos): Add constraints for a result decl that is passed by hidden reference. (build_pred_graph): Mark all related variables non-direct on address-taking. * gcc.dg/Wstrict-aliasing-bogus-pta-1.c: New testcase. Added: trunk/gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-pta-1.c Modified: trunk/gcc/ChangeLog trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-ssa-structalias.c
Fixed.