I've stumbled upon what looks like a compiler bug with the following code, compiled for aarch64: #include <cassert> #include <boost/bimap.hpp> #include <boost/bimap/unordered_set_of.hpp> int main() { using map_type = boost::bimap<boost::bimaps::set_of<int>, boost::bimaps::unordered_set_of<int>>; map_type map; auto x = map.insert({0, 0}).first; map.replace_right(x, 42); auto y = map.find(map_type::value_type{0, 42}); assert(y != map.end()); assert(x == y); assert(&x->right == &y->right); assert(y->right != 0); assert(x->right != 0); } The last assert fails with -O2. I've managed to track the optimization flags down to -O1 -fcode-hoisting -fipa-sra -fstrict-aliasing . In the .s, it looks like x is kept in register x19 while x->right is kept in w23, but after the call to replace_right, w23 is not updated using x19 and thus holds the old value (0). I've tested that with GCC master (e9fb6efa1cf542353fd44ddcbb5136344c463fd0) and Boost/bimap master (6865e94cc56a33bb8b162bf8d62cfe620b06d2b6), cross-compiled with GCC 13.2.0-23ubuntu4 for aarch64 using Buildroot 2024.02.1 with the following configure flags: Using built-in specs. COLLECT_AS_OPTIONS='--version' COLLECT_GCC=[...]/host/bin/aarch64-linux-g++.br_real COLLECT_LTO_WRAPPER=[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/lto-wrapper aarch64-linux-g++.br_real (Buildroot 2024.02.1-6309-g2fd20014a8) 15.0.0 20240703 (experimental) Copyright (C) 2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Target: aarch64-buildroot-linux-musl Configured with: ./configure --prefix=[...]/host --sysconfdir=[...]/host/etc --enable-static --target=aarch64-buildroot-linux-musl --with-sysroot=[...]/host/aarch64-buildroot-linux-musl/sysroot --enable-__cxa_atexit --with-gnu-ld --disable-libssp --disable-multilib --disable-decimal-float --enable-plugins --enable-lto --with-gmp=[...]/host --with-mpc=[...]/host --with-mpfr=[...]/host --with-pkgversion='Buildroot 2024.02.1-6309-g2fd20014a8' --with-bugurl=http://bugs.buildroot.net/ --without-zstd --with-debug-prefix-map=[...]=buildroot --disable-libmpx --disable-libquadmath --disable-libquadmath-support --disable-libsanitizer --enable-tls --enable-threads --without-isl --without-cloog --with-abi=lp64 --with-cpu=cortex-a53 --enable-languages=c,c++ --with-build-time-tools=[...]/host/aarch64-buildroot-linux-musl/bin --enable-shared --disable-libgomp Thread model: posix Supported LTO compression algorithms: zlib gcc version 15.0.0 20240703 (experimental) (Buildroot 2024.02.1-6309-g2fd20014a8) COMPILER_PATH=[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/:[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/:[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/:[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/:[...]/host/lib/gcc/aarch64-buildroot-linux-musl/:[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/bin/ LIBRARY_PATH=[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/:[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib/../lib64/:[...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/:[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib/../lib64/:[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib/:[...]/host/aarch64-buildroot-linux-musl/sysroot/lib/:[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib/ COLLECT_GCC_OPTIONS='--sysroot=[...]/host/aarch64-buildroot-linux-musl/sysroot' '-fstack-protector-strong' '-ffile-prefix-map=[...]=buildroot' '-fPIE' '-pie' '--version' '-v' '-shared-libgcc' '-mcpu=cortex-a53' '-mlittle-endian' '-mabi=lp64' '-dumpdir' 'a.' [...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/collect2 -plugin [...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/liblto_plugin.so -plugin-opt=[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccP2tEjt.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=[...]/host/aarch64-buildroot-linux-musl/sysroot --eh-frame-hdr -dynamic-linker /lib/ld-musl-aarch64.so.1 -X -EL -maarch64linux -pie --version [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/Scrt1.o [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/crti.o [...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/crtbeginS.o -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0 -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib/../lib64 -L[...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64 -L[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib/../lib64 -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib -L[...]/host/aarch64-buildroot-linux-musl/sysroot/lib -L[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib -z max-page-size=4096 -z common-page-size=4096 --build-id=none -z relro -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc [...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/crtendS.o [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/crtn.o collect2 version 15.0.0 20240703 (experimental) [...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/bin/ld -plugin [...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/liblto_plugin.so -plugin-opt=[...]/host/libexec/gcc/aarch64-buildroot-linux-musl/15.0.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccP2tEjt.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=[...]/host/aarch64-buildroot-linux-musl/sysroot --eh-frame-hdr -dynamic-linker /lib/ld-musl-aarch64.so.1 -X -EL -maarch64linux -pie --version [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/Scrt1.o [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/crti.o [...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/crtbeginS.o -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0 -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib/../lib64 -L[...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64 -L[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib/../lib64 -L[...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/../../../../aarch64-buildroot-linux-musl/lib -L[...]/host/aarch64-buildroot-linux-musl/sysroot/lib -L[...]/host/aarch64-buildroot-linux-musl/sysroot/usr/lib -z max-page-size=4096 -z common-page-size=4096 --build-id=none -z relro -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc [...]/host/lib/gcc/aarch64-buildroot-linux-musl/15.0.0/crtendS.o [...]/host/aarch64-buildroot-linux-musl/sysroot/lib/../lib64/crtn.o GNU ld (GNU Binutils) 2.40 Copyright (C) 2023 Free Software Foundation, Inc. This program is free software; you may redistribute it under the terms of the GNU General Public License version 3 or (at your option) a later version. This program has absolutely no warranty. COLLECT_GCC_OPTIONS='--sysroot=[...]/host/aarch64-buildroot-linux-musl/sysroot' '-fstack-protector-strong' '-ffile-prefix-map=[...]=buildroot' '-fPIE' '-pie' '--version' '-v' '-shared-libgcc' '-mcpu=cortex-a53' '-mlittle-endian' '-mabi=lp64' '-dumpdir' 'a.'
Created attachment 58581 [details] The preprocessed source file.
On amd64, it starts to fail with 11.
(In reply to Sam James from comment #2) > On amd64, it starts to fail with 11. Oh yes, indeed. I've overlooked that fact.
Note that -fno-strict-aliasing helps and in the boost code path for replace_right there's: return *reinterpret_cast< const View* >(boost::addressof(m)); But maybe this line is innocent and -fno-strict-aliasing just happens to hide the issue somehow OTOH.
FWIW, I ran a git bisect from releases/gcc-10.5.0 to releases/gcc-11.1.0 and the first bad commit is d119f34c952f8718fdbabc63e2f369a16e92fa07, which adds modref/ipa_modref optimization passes.
There are some open IPA modref issues, thanks for bisecting. I hope Honza will look at this and the others.
GCC 11 branch is being closed.
While we wait for Honza, Ignacy, if you could try reduce it to get rid of the Boost dependency, it'd be appreciated. You can cvise for runtime testcases, just add several checks with different compilers and UBSAN and friends.
(In reply to Sam James from comment #8) > While we wait for Honza, Ignacy, if you could try reduce it to get rid of > the Boost dependency, it'd be appreciated. I'm struggling to get a minimal example. I found what looks like a bug in Boost Bimap along the way, but it makes the problem go away only on x86_64, not on aarch64. I tried to find strict aliasing violations in the code by disabling ipa-modref on smaller and smaller parts of the execution path (using a function attribute), while checking that the problem goes away. All I ended up with was a method so simple that I can tell for sure it doesn't violate anything, and still, removing the attribute on it makes the problem appear. I believe the appearance of the problem is sensitive to even slight changes in register allocation, which makes finding a minimal example a very difficult task. > You can cvise for runtime testcases, just add several checks with different > compilers and UBSAN and friends. I tried to run cvise on the preprocessed code with no success at all. All the resulting code I got after hours of processing was either trivially useless (as it did not reproduce the problem), or did not compile at all. I suppose my lack of experience with this tool is to blame.
Could you try trunk or the 14.2 RC1? A bunch of IPA fixes landed.
(In reply to Sam James from comment #10) > Could you try trunk or the 14.2 RC1? A bunch of IPA fixes landed. I tested with 162a1ed70303a031c81b0aaac499aaf394560390 and the problem is still there with vanilla Boost Bimap, but apparently goes away with my patch (https://github.com/boostorg/bimap/pull/45). I then ran a bisect and found that the first commit that makes the problem disappear on aarch64 with the patched Boost Bimap is 03a810da10d8dfb5aec9261372cad7bf090e6986. The commit message doesn't look like it is related to ipa-modref, but maybe I simply have no clue or this is just a coincidence. It is hard for me to tell for sure.
(In reply to Ignacy Gawędzki from comment #11) > I then ran a bisect and found that the first commit that makes the problem > disappear on aarch64 with the patched Boost Bimap is > 03a810da10d8dfb5aec9261372cad7bf090e6986. I wouldn't expect it to.
I am going to try to reduce this.
Created attachment 60024 [details] First step, remove some unused code
Created attachment 60025 [details] Checkpoint
Created attachment 60029 [details] checkpoint2
Created attachment 60030 [details] Checkpoint3 This time no need to compress
There might be a strict aliasing violation dealing with iterators. I am not 100% yet though.
So far in my reduced testcase: This fails: auto find() { return this->template functor<typename base_::iterator_from_base>()( this->base().find(0)); } While this works: auto find() { return this->base().find(0); } Which is why I said there seems to be some aliasing issue with iterators.
Created attachment 60031 [details] checkpoint4
Might be an aliasing problem or may be a codegen issue. The former obviously makes this INVALID, the latter would start as a P1 issue.
Maybe it's worthy to try the new LLVM TBAA sanitizer for this?
(In reply to Xi Ruoyao from comment #22) > Maybe it's worthy to try the new LLVM TBAA sanitizer for this? Good idea. It has no complaints.
It can only be P2 since we shipped countless releases with it.
I used creduce and some de-namespacing and brought it to about 60k lines, I hope to post the checkpoint soon
(In reply to mcccs from comment #25) > I used creduce and some de-namespacing and brought it to about 60k lines, I > hope to post the checkpoint soon Thank you! Even partial reductions often help a lot (though do keep going) because it makes it way easier to spot problematic lines.
*sorry I meant 60k bytes not lines
Created attachment 61145 [details] 27k bytes reduced testcase further reduced with c-reduce. verified with various LLVM fsanitize's
fails with even -O1 -fstrict-aliasing -fcode-hoisting
Comment on attachment 61145 [details] 27k bytes reduced testcase >template <int a> struct b { > static const int c = a; >}; >struct e {}; >template <int> struct aa; >template <typename = e, typename = int> struct ab; >template <> struct aa<1> { > template <typename h, typename, typename, typename, typename> struct ac { > typedef h d; > }; >}; >template <> struct aa<2> { > template <typename, typename ad, typename, typename, typename> struct ac { > typedef ad d; > }; >}; >template <typename> struct ae {}; >template <typename> struct as; >template <typename g> struct ae<ae<g>> { > typedef g d; >}; >template <class g, g af> struct i { > static const int c = af; >}; >template <class, class> struct j : i<int, 0> {}; >template <class g> struct j<g, g> : i<int, 1> {}; >template <typename ag = e, typename g = e> >struct ah : ae<typename ag::ai>::template ac<ag, g> {}; >template <> struct ah<> { > template <typename aj, typename ak> struct ac : ah<aj, ak> {}; >}; >template <int, typename aj, typename> struct al { > typedef aj d; >}; >template <typename aj, typename ak> struct al<0, aj, ak> { > typedef ak d; >}; >template <typename aj, typename ak, typename am> struct an { > typedef typename al<aj::c, ak, am>::d d; >}; >template <int at> struct ao { > static const int c = at; > typedef ao<at + 1> ar; >}; >template <typename aw, int ax> struct au { > typedef __typeof__(aw::av(ao<ax>())) d; >}; >template <typename aw, int ax> struct bb : ae<typename au<aw, ax>::d> {}; >template <> struct as<int> { > template <typename aw, typename at> struct ac : bb<aw, at::c> {}; >}; >template <typename g> struct ar { > typedef typename g::ar d; >}; >template <typename g, typename bc> struct ay : bc { > typedef typename bc::az ba; > typedef typename ba::ar az; > typedef typename ar<typename bc::bg>::d bg; > static ae<g> av(ba); > using bc::av; >}; >template <> struct ae<int> { > template <typename aw, typename g> struct ac { > typedef ay<g, aw> d; > }; >}; >template <typename bd, typename aj, typename ak> >struct be : bd::template ac<aj, ak> {}; >template <typename bd, typename aj, typename am> >struct bf : bd::template ac<aj, int, am> {}; >template <typename bd, typename aj, typename ak> >struct bl : bd::template ac<aj, ak, int, int, int> {}; >template <typename bh, typename bi, typename k = e> struct bj { > typedef typename an<bh, bi, k>::d ::d d; >}; >template <int bh, typename bi, typename k> struct bk { > typedef typename al<bh, bi, k>::d ::d d; >}; >template <typename aw, long ax> struct bp { > typedef typename bb<aw, ax>::d d; >}; >template <typename aw, long ax> struct ar<bp<aw, ax>> { > typedef bp<aw, ax + 1> d; >}; >struct bm { > typedef int ai; > typedef ao<0> az; > typedef ao<0> bg; > void av(); >}; >template <typename aw> struct ac : aw::bg {}; >struct bn { > template <typename aw> struct ac { > typedef bp<aw, 0> d; > }; >}; >template <typename bo> struct bv : ay<bo, bm> {}; >template <typename bo, typename aj> struct bq : ay<aj, bv<bo>> {}; >template <typename bo, typename aj, typename ak> >struct br : ay<ak, bq<bo, aj>> {}; >template <typename bo, typename aj, typename ak, typename am> >struct bs : ay<am, br<bo, aj, ak>> {}; >template <typename = e, typename = e, typename = e, typename = e, typename = e> >struct bt; >template <> struct bt<> : bm {}; >template <typename bo> struct bt<bo> : bv<bo> {}; >template <typename bo, typename aj, typename ak, typename am> >struct bt<bo, aj, ak, am> : bs<bo, aj, ak, am> {}; >template <typename> struct allocator { > template <typename bu> allocator(bu) {} >}; >template <typename> struct cf; >template <typename bw> struct cf<allocator<bw>> { > using bx = bw *; > template <typename by> using bz = allocator<by>; > static bx allocate() { return (bx)__builtin_calloc(1, sizeof(bw)); } >}; >template <class g> struct ca { > typedef g &d; >}; >template <typename ag> struct begin { > typedef typename bn::ac<ag>::d d; >}; >template <typename ag, int at> >struct cb : as<typename ag::ai>::template ac<ag, ao<at>> {}; >template <typename g> struct cd : g {}; >template <typename, typename, typename, typename> struct ce; >template <int at, typename h, typename ad, typename cp> >struct ce<aa<at>, h, ad, cp> { > typedef typename bl<aa<at>, h, ad>::d d; >}; >struct l; >template <typename, typename, typename> struct cg { > template <typename, typename ad> struct ac { > typedef typename be<l, typename ce<aa<2>, int, ad, int>::d, > typename ce<aa<1>, int, ad, int>::d>::d d; > }; >}; >template <template <typename, typename, typename> class> struct ch; >struct m; >template <typename am> struct ci { > template <typename h, typename ad> struct ac { > typedef typename bf<ch<an>, m, typename ce<am, h, ad, int>::d>::d d; > }; >}; >template <typename bd, typename aj, typename ak, typename, typename, typename> >struct cj { > template <typename h, typename ad, typename, typename, typename> struct ac { > typedef typename bl<bd, typename ce<aj, h, ad, int>::d, > typename ce<ak, h, ad, int>::d>::d d; > }; >}; >template <typename bd, typename aj, typename ak, typename am, typename ap, > typename aq, typename h, typename ad, typename cp> >struct ce<cj<bd, aj, ak, am, ap, aq>, h, ad, cp> { > typedef typename bl<cj<bd, aj, ak, am, ap, aq>, h, ad>::d d; >}; >template <typename g> struct ck { > typedef typename g::d d; >}; >template <template <typename, typename, typename> class bd> struct ch { > template <typename h, typename, typename cl> > struct ac : ck<bd<h, int, cl>> {}; >}; >template <template <typename, typename, typename, typename, typename> class bd> >struct cw { > template <typename h, typename ad, typename, typename, typename> > struct ac : ck<bd<h, ad, int, int, int>> {}; >}; >template <typename g, typename> struct ab { > typedef g cm; > typedef g d; >}; >template <typename bd, typename aj, typename ak, typename cn> >struct ab<cg<bd, aj, ak>, cn> { > typedef cg<bd, aj, ak> d; >}; >template <typename co> struct da { > typedef cd<ci<typename co::cm>> d; >}; >template <template <typename, typename, typename> class bd, typename aj, > typename ak, typename am, typename cn> >struct ab<bd<aj, ak, am>, cn> { > typedef typename da<ab<am>>::d d; >}; >template <typename, > template <typename, typename, typename, typename, typename> class, > typename, typename, typename, typename, typename> >struct cq; >template <template <typename, typename, typename, typename, typename> class bd, > typename cr, typename cs, typename co, typename ct, typename cu> >struct cq<b<1>, bd, cr, cs, co, ct, cu> { > typedef cj<cw<bd>, typename cr::cm, typename cs::cm, typename co::cm, > typename ct::cm, typename cu::cm> > cm; >}; >template <template <typename, typename, typename, typename, typename> class bd, > typename aj, typename ak, typename am, typename ap, typename aq, > typename cn> >struct ab<bd<aj, ak, am, ap, aq>, cn> { > typedef typename cq<b<1>, bd, ab<aj>, ab<ak>, ab<>, ab<>, ab<>>::cm cm; >}; >template <typename bd, typename aj, typename ak> >struct cv : be<typename ab<bd>::d, aj, ak> {}; >template <typename ak> struct n { > typedef ak dl; >}; >template <typename g> struct cx { > typedef g d; >}; >template <typename ag> struct o { > typedef n<typename begin<ag>::d> d; >}; >template <typename ag> struct p { > typedef typename o<ag>::d ::dl d; >}; >template <int, typename, typename, typename> struct q; >template <typename cy, typename cz, typename s> struct q<4, cy, cz, s> { > typedef cy t; > typedef typename ar<t>::d v; > typedef typename ar<v>::d u; > typedef typename ar<u>::d x; > typedef typename cv< > s, > typename cv<s, > typename cv<s, typename cv<s, cz, typename t::d>::d, > typename v::d>::d, > typename u::d>::d, > typename x::d>::d db; >}; >template <typename ag, typename cz, typename s> struct dc { > typedef typename q<ac<ag>::c, typename begin<ag>::d, cz, s>::db d; >}; >struct y { > typedef bt<> db; > typedef ah<> dd; >}; >template <typename, typename, typename> struct w; >template <typename de, typename g> struct df { > typedef typename cf<de>::template bz<g> d; >}; >template <int, typename, typename, typename> struct dg; >template <typename cy, typename dh, typename s> struct dg<2, cy, dh, s> { > typedef cy t; > typedef typename cv<dh, typename cv<dh, int, typename ar<t>::d>::d, t>::d db; >}; >template <typename ag, typename dh> struct dj { > typedef typename dg<ac<ag>::c, typename begin<ag>::d, dh, int>::db d; >}; >template <typename dk, typename Final> struct dm { > dm() : member(static_cast<Final *>(this)->z()) {} > dk member; >}; >template <typename Value, typename de> struct index_node_base { > int space; > typedef Value cc; > typedef de allocator_type; > cc &c() { return *reinterpret_cast<cc *>(&space); } >}; >struct l { > template <typename IndexSpecifierIterator, typename> struct ac { > typedef typename IndexSpecifierIterator::d ::template node_class<int>::d d; > }; >}; >template <typename IndexSpecifierList> struct multi_index_node_type { > typedef typename dj<IndexSpecifierList, cg<int, int, int>>::d d; >}; >template <typename g> struct add_pointer { > typedef g *d; >}; >template <class TT> struct cons { > TT tail; >}; >template <typename Value, typename IndexSpecifierList, typename de> >struct index_base { > typedef typename multi_index_node_type<IndexSpecifierList>::d final_node_type; > typedef w<Value, IndexSpecifierList, de> final_type; > typedef int ctor_args_list; > typedef typename df<de, int>::d final_allocator_type; > typedef bm index_type_list; > typedef Value cc; > index_base(ctor_args_list, de) {} > final_node_type *insert_(cc, final_node_type *&p2) { > return p2 = final().z(); > } > void replace_(cc p1, index_node_base<Value, de> *p2, int) { p2->c() = p1; } > final_type final() { return *static_cast<final_type *>(this); } > final_node_type *final_header() { return final().header(); } > final_node_type *final_insert_(cc p1) { return final().insert_(p1); } > void final_replace_rv_(cc p1, final_node_type *p2) { > final().replace_rv_(p1, p2); > } >}; >struct index_applier { > template <typename IndexSpecifierMeta, typename SuperMeta> struct ac { > typedef > typename IndexSpecifierMeta::d ::template index_class<SuperMeta>::d d; > }; >}; >template <int at, typename Value, typename IndexSpecifierList, typename de> >struct nth_layer { > typedef > typename bk<at == ao<2>::c, cx<index_base<Value, IndexSpecifierList, de>>, > cv<index_applier, cb<IndexSpecifierList, at>, > nth_layer<at + 1, Value, IndexSpecifierList, de>>>::d d; >}; >template <class, class, class, bool> struct mutant_relation; >template <typename IndexSpecifierList, typename de> >struct multi_index_base_type > : nth_layer<0, mutant_relation<int, int, e, 1>, IndexSpecifierList, de> {}; >template <typename Value, typename IndexSpecifierList, typename de> >struct w > : dm<typename cf<typename df< > de, typename multi_index_node_type<IndexSpecifierList>::d>::d>::bx, > w<Value, IndexSpecifierList, de>>, > multi_index_base_type<IndexSpecifierList, de>::d { > typedef typename multi_index_base_type<IndexSpecifierList, de>::d super; > typedef cf<typename df<de, typename super::index_node_type>::d> > node_alloc_traits; > typedef dm<typename node_alloc_traits::bx, w> bfm_header; > typedef typename super::final_node_type final_node_type; > w(typename super::final_allocator_type) > : super(typename super::ctor_args_list(), 0) {} > template <typename> struct index { > typedef typename p<typename super::index_type_list>::d ::d d; > }; > final_node_type *header() { return bfm_header::member; } > final_node_type *z() { return node_alloc_traits::allocate(); } > final_node_type *insert_(Value p1) { return super::insert_(p1, 0); } > void replace_rv_(Value p1, final_node_type *p2) { > super::replace_(p1, p2, 0); > } >}; >template <class, class Type> mutant_relation<int, int, e, 0> &mutate(Type &p1) { > return *reinterpret_cast<mutant_relation<int, int, e, 0> *>( > __builtin_addressof(p1)); >} >struct relation_info_hook { > int right; > relation_info_hook(int, int p2) : right(p2) {} >}; >template <class, class, class Info, bool> >struct mutant_relation : relation_info_hook { > typedef mutant_relation<int, int, Info, 0> above_view; > mutant_relation(int, int p2) : relation_info_hook(0, p2) {} > mutant_relation(const mutant_relation<int, int, Info, 0> &p1) > : relation_info_hook(p1) {} > above_view &get_view() { return mutate<above_view>(*this); } >}; >template <class TA, class TB, bool force_mutable> >mutant_relation<TA, TB, e, 0> >copy_with_right_replaced(mutant_relation<TA, TB, e, force_mutable>, int p2) { > return mutant_relation<TA, TB, e, 0>(0, p2); >} >struct m : i<int, 0> {}; >struct use_default; >template <class ValueParam> struct iterator_facade_types { > typedef typename bj<b<1>, add_pointer<ValueParam>>::d bx; >}; >template <class g, class Pointer> struct operator_arrow_dispatch { > static Pointer ac(g p1) { return __builtin_addressof(p1); } >}; >template <class, class, class, class, int> struct iterator_facade_base; >template <class Derived, class Value, class Reference, class Difference> >struct iterator_facade_base<Derived, Value, Reference, Difference, 0> { > typedef iterator_facade_types<Value> associated_types; > typedef Reference reference; > reference operator*() { return derived().dereference(); } > typename associated_types::bx operator->() { > return operator_arrow_dispatch< > Reference, typename associated_types::bx>::ac(*derived()); > } > Derived derived() { return *static_cast<Derived *>(this); } >}; >template <class Derived, class Value, class Reference> >struct iterator_facade > : iterator_facade_base<Derived, Value, Reference, int, i<int, 0>::c> {}; >template <class g, class DefaultNullaryFn> >struct ia_dflt_help : bj<j<g, use_default>, DefaultNullaryFn, cx<g>> {}; >template <class Derived, class Value, class Reference> >struct iterator_adaptor_base { > typedef iterator_facade< > Derived, typename ia_dflt_help<Value, int>::d, > typename ia_dflt_help<Reference, > bj<j<Value, use_default>, int, ca<Value>>>::d> > d; >}; >template <class Derived, class bc, class Value, class Reference = use_default> >struct Trans_NS_iterators_iterator_adaptor > : iterator_adaptor_base<Derived, Value, Reference>::d { > Trans_NS_iterators_iterator_adaptor(bc p1) : m_iterator(p1) {} > typedef bc base_type; > bc m_iterator; >}; >template <typename Node> struct bidir_node_iterator { > bidir_node_iterator(Node *p1) : node(p1) {} > typename Node::cc &operator*() { return node->c(); } > Node *node; >}; >template <typename> struct ordered_index_node_impl_; >struct null_augment_policy; >struct ordered_index_node_compressed_base { > typedef ordered_index_node_impl_<allocator<char>> *bx; > struct parent_ref { > parent_ref(long *p1) : r(p1) {} > operator bx() { return bx(*r); } > long *r; > }; > parent_ref parent() { return &parentcolor_; } > long parentcolor_; >}; >template <typename AugmentPolicy, typename> >struct ordered_index_node_impl_base > : AugmentPolicy::template augmented_node<int>::d {}; >template <typename de> >struct ordered_index_node_impl_ > : ordered_index_node_impl_base<null_augment_policy, de> { > typedef typename ordered_index_node_impl_base<null_augment_policy, de>::bx bx; > static void link(bx p1, bx p2) { *p2->parent().r = (long)p1; } >}; >template <typename Super> >struct ordered_index_node_trampoline > : ordered_index_node_impl_< > typename df<typename Super::allocator_type, char>::d> { > typedef ordered_index_node_impl_<int> impl_type; >}; >template <typename Super> >struct ordered_index_node : Super, ordered_index_node_trampoline<Super> { > static ordered_index_node * > from_impl_(typename ordered_index_node_trampoline<Super>::bx p1) { > return static_cast<ordered_index_node *>(p1); > } >}; >template <typename SuperMeta> struct ordered_index_impl_ : SuperMeta::d { > typedef typename SuperMeta::d super; > typedef ordered_index_node<typename super::index_node_type> index_node_type; > typedef typename index_node_type::impl_type node_impl_type; > typedef typename index_node_type::cc cc; > typedef bidir_node_iterator<index_node_type> dn; > typedef typename super::final_node_type final_node_type; > typedef cons<typename super::ctor_args_list> ctor_args_list; > dn insert(cc p1) { return this->final_insert_(p1); } > void replace(dn p1, cc p2) { this->final_replace_rv_(p2, p1.node); } > template <typename CompatibleKey> dn find(CompatibleKey) { > return index_node_type::from_impl_(this->final_header()->parent()); > } > ordered_index_impl_(ctor_args_list p1, typename super::final_allocator_type) > : super(p1.tail, 0) {} > final_node_type *insert_(cc p1, final_node_type *p2) { > final_node_type *f = super::insert_(p1, p2); > node_impl_type::link(p2, this->final_header()); > return f; > } >}; >template <typename SuperMeta, typename AugmentPolicy> >struct ordered_index : AugmentPolicy::template augmented_interface< > ordered_index_impl_<SuperMeta>>::d { > typedef typename AugmentPolicy::template augmented_interface< > ordered_index_impl_<SuperMeta>>::d super; > ordered_index(typename super::ctor_args_list p1, > typename super::allocator_type) > : super(p1, 0) {} >}; >struct null_augment_policy { > template <typename OrderedIndexImpl_> struct augmented_interface { > typedef OrderedIndexImpl_ d; > }; > template <typename> struct augmented_node { > typedef ordered_index_node_compressed_base d; > }; >}; >struct ordered_unique { > template <typename> struct node_class { > typedef ordered_index_node< > index_node_base<mutant_relation<int, int, e, 1>, allocator<char>>> > d; > }; > template <typename SuperMeta> struct index_class { > typedef ordered_index<SuperMeta, null_augment_policy> d; > }; >}; >template <class BaseIterator, class di> struct iterator_from_base_identity { > di operator()(BaseIterator p1) { return p1; } >}; >template <typename Types_, typename Node_, typename Root_ = e> >struct inherit_linearly : dc<Types_, Root_, Node_> {}; >template <typename aj, typename ak> struct inherit2 : aj, ak { > typedef inherit2 d; >}; >template <typename aj, typename ak, typename = e, typename = e, typename = e> >struct inherit5 : inherit2<aj, ak> {}; >template <class Data, class FunctorList> >struct data_with_functor_bag > : inherit_linearly<FunctorList, an<m, int, inherit5<aa<1>, aa<2>>>>::d { > Data data; > data_with_functor_bag(Data p1) : data(p1) {} >}; >template <typename ag, typename Inserter> >struct copy_impl_ : dc<ag, typename Inserter::db, typename Inserter::dd> {}; >template <class bc, class di, class IteratorToBaseConverter> >struct Trans_NS_container_adaptor_container_adaptor { > typedef di dn; > typedef iterator_from_base_identity<dn, dn> iterator_from_base; > Trans_NS_container_adaptor_container_adaptor(bc &p1) : dwfb(p1) {} > typedef bc base_type; > template <class Functor> Functor functor() { return dwfb; } > data_with_functor_bag< > bc &, > typename copy_impl_<bt<typename an<b<0>, int, IteratorToBaseConverter>::d, > iterator_from_base>, > y>::d> > dwfb; >}; >template <class bc, class di, class IteratorToBaseConverter> >struct associative_container_adaptor_base { > typedef Trans_NS_container_adaptor_container_adaptor<bc, di, > IteratorToBaseConverter> > d; >}; >template <class bc, class di, class IteratorToBaseConverter> >struct associative_container_adaptor > : associative_container_adaptor_base<bc, di, IteratorToBaseConverter>::d { > typedef typename associative_container_adaptor_base< > bc, di, IteratorToBaseConverter>::d base_; > associative_container_adaptor(bc &p1) : base_(p1) {} > auto find() { > return this->template functor<typename base_::iterator_from_base>()( > this->dwfb.data.find(0)); > } >}; >template <class bc, class di, class IteratorToBaseConverter> >struct ordered_associative_container_adaptor_base { > typedef associative_container_adaptor<bc, di, IteratorToBaseConverter> d; >}; >template <class bc, class di, class IteratorToBaseConverter> >struct ordered_associative_container_adaptor > : ordered_associative_container_adaptor_base<bc, di, > IteratorToBaseConverter>::d { > typedef typename ordered_associative_container_adaptor_base< > bc, di, IteratorToBaseConverter>::d base_; > ordered_associative_container_adaptor(bc &p1) : base_(p1) {} >}; >template <class bc, class IteratorToBaseConverter> >struct map_adaptor > : ordered_associative_container_adaptor<bc, int, IteratorToBaseConverter> { > map_adaptor(bc p1) > : ordered_associative_container_adaptor<bc, int, IteratorToBaseConverter>( > p1) {} >}; >template <class di> struct iterator_facade_to_base { > typename di::base_type operator()(di p1) { return p1.m_iterator; } >}; >template <class BimapType> >struct map_view > : map_adaptor<typename BimapType::core_type::template index<int>::d, > iterator_facade_to_base< > Trans_NS_iterators_iterator_adaptor<int, int, int>>> { > typedef map_adaptor<typename BimapType::core_type::template index<int>::d, > iterator_facade_to_base< > Trans_NS_iterators_iterator_adaptor<int, int, int>>> > base_; > map_view(typename base_::base_type p1) : base_(p1) {} >}; >template <class bc, class di, class IteratorToBaseConverter> >struct set_adaptor > : ordered_associative_container_adaptor<bc, di, IteratorToBaseConverter> { > set_adaptor(bc &p1) > : ordered_associative_container_adaptor<bc, di, IteratorToBaseConverter>( > p1) {} >}; >struct set_view_iterator > : Trans_NS_iterators_iterator_adaptor< > set_view_iterator, > bidir_node_iterator<ordered_index_node<index_node_base< > mutant_relation<int, int, e, 1>, allocator<char>>>>, > mutant_relation<int, int, e, 0>> { > set_view_iterator( > bidir_node_iterator<ordered_index_node< > index_node_base<mutant_relation<int, int, e, 1>, allocator<char>>>> > p1) > : Trans_NS_iterators_iterator_adaptor(p1) {} > reference dereference() { return (&*m_iterator)->get_view(); } >}; >template <class CoreIndex> >struct set_view : set_adaptor<CoreIndex, set_view_iterator, > iterator_facade_to_base<set_view_iterator>> { > typedef set_adaptor<CoreIndex, set_view_iterator, > iterator_facade_to_base<set_view_iterator>> > base_; > set_view(typename base_::base_type &p1) : base_(p1) {} > void replace_right(set_view_iterator p1, int p2) { > this->dwfb.data.replace( > this->template functor<iterator_facade_to_base<set_view_iterator>>()( > p1), > copy_with_right_replaced(*p1, p2)); > } >}; >struct set_of { > template <class, class BimapType> struct map_view_bind { > typedef map_view<BimapType> d; > }; > template <class IndexType> struct set_view_bind { > typedef set_view<IndexType> d; > }; >}; >struct unordered_set_of; >template <class RightSetType, class> struct bimap_core { > typedef set_of left_set_type; > typedef RightSetType right_set_type; > typedef int left_tag; > typedef int right_tag; > typedef typename an<b<0>, int, > typename ah<bt<ordered_unique>, > typename right_set_type::template index_bind< > int, right_tag>::d>::d>::d > compl_ete_core_indices; > struct core_indices : compl_ete_core_indices {}; > typedef w<int, core_indices, allocator<char>> core_type; > typedef typename left_set_type::set_view_bind<core_type>::d relation_set; >}; >template <class BimapBaseType> struct left_map_view_type { > typedef typename BimapBaseType::left_set_type::template map_view_bind< > typename BimapBaseType::left_tag, BimapBaseType>::d d; >}; >template <class BimapBaseType> struct right_map_view_type { > typedef typename BimapBaseType::right_set_type::template map_view_bind< > typename BimapBaseType::right_tag, BimapBaseType>::d d; >}; >template <class AP1 = e> >struct bimap : bimap_core<unordered_set_of, AP1>::relation_set { > typedef bimap_core<unordered_set_of, AP1> base_; > typename base_::core_type core; > typename left_map_view_type<base_>::d left; > typename right_map_view_type<base_>::d right; > bimap() : base_::relation_set(core), core(0), left(core), right(core) {} >}; >template <typename SuperMeta> struct hashed_index : SuperMeta::d { > typedef typename SuperMeta::d super; > typedef index_node_base<mutant_relation<int, int, e, 1>, allocator<char>> > index_node_type; > typedef typename super::final_allocator_type allocator_type; > typedef cons<typename super::ctor_args_list> ctor_args_list; > typedef typename ah<typename super::index_type_list, hashed_index>::d > index_type_list; > hashed_index(ctor_args_list, allocator_type) : super(0, 0) {} >}; >struct hashed_unique { > template <typename> struct node_class { > typedef index_node_base<mutant_relation<int, int, int, 0>, int> d; > }; > template <typename SuperMeta> struct index_class { > typedef hashed_index<SuperMeta> d; > }; >}; >template <class bc, class IteratorToBaseConverter> >struct unordered_associative_container_adaptor_base { > typedef associative_container_adaptor<bc, int, IteratorToBaseConverter> d; >}; >template <class bc, class IteratorToBaseConverter> >struct unordered_associative_container_adaptor > : unordered_associative_container_adaptor_base<bc, > IteratorToBaseConverter>::d { > typedef typename unordered_associative_container_adaptor_base< > bc, IteratorToBaseConverter>::d base_; > unordered_associative_container_adaptor(bc p1) : base_(p1) {} >}; >template <class bc, class IteratorToBaseConverter> >struct unordered_map_adaptor > : unordered_associative_container_adaptor<bc, IteratorToBaseConverter> { > unordered_map_adaptor(bc p1) > : unordered_associative_container_adaptor<bc, IteratorToBaseConverter>( > p1) {} >}; >template <class BimapType> >struct unordered_map_view > : unordered_map_adaptor< > typename BimapType::core_type::template index<int>::d, > iterator_facade_to_base< > Trans_NS_iterators_iterator_adaptor<int, int, int>>> { > typedef unordered_map_adaptor< > typename BimapType::core_type::template index<int>::d, > iterator_facade_to_base< > Trans_NS_iterators_iterator_adaptor<int, int, int>>> > base_; > unordered_map_view(typename base_::base_type p1) : base_(p1) {} >}; >struct unordered_set_of { > template <class, class> struct index_bind { > typedef hashed_unique d; > }; > template <class, class> struct map_view_bind { > typedef unordered_map_view<bimap_core<unordered_set_of, e>> d; > }; >}; >int main() { > bimap d; > d.replace_right(d.dwfb.data.insert({0, 0}), 42); > if (d.find()->right != 42) > __builtin_abort(); >}
Created attachment 61160 [details] minimized.cpp GCC -O1 -fstrict-aliasing or -O2 or -O3: aborts I've attached the minimized human-readable reduced file. I do think it demonstrates GCC's fault in the original file, because if you: change reinterpret_cast<templated_long_s<1> *> near the end of the file to reinterpret_cast<templated_long_s<0> *>, which has the exact same memory layout (the template parameter is a dummy parameter), the produced assembly changes and execution does not abort. ---- Comparing the "optimized" pass output with and without this mutation, it's seen that MEM[(struct templated_long_s *)_9].right = 42; only exists in the correct version. Therefore the testcase has the line reinterpreted->right = 42; completely dropped due to optimization. ---- To experiment with the testcase, you may replace all 4 occurences of "long long" with "long" or "int".
Oh no I'm so sorry all! I tried to set the previous attachment obsolete unfortunately it quoted all of it and posted here! Sorry for the tall thread
(In reply to mcccs from comment #31) > Created attachment 61160 [details] > minimized.cpp > > GCC -O1 -fstrict-aliasing or -O2 or -O3: aborts > > I've attached the minimized human-readable reduced file. I do think it > demonstrates GCC's fault in the original file, because if you: > > change reinterpret_cast<templated_long_s<1> *> near the end of the file to > reinterpret_cast<templated_long_s<0> *>, which has the exact same memory > layout (the template parameter is a dummy parameter), the produced assembly > changes and execution does not abort. This reduced testcase is definitely undefined because templated_long_s<1> and templated_long_s<0> are not compatiable types; they might have the same layout but they are not compatiable types for aliasing rules.
Thanks Andrew for the reply. In that case, the issue is probably invalid because checkpoint4.cpp also has several reinterpret_casts casting to things involving templates. Too bad, LLVM's -fsanitize=undefined and -fsanitize=type don't print any errors for this
GCC 12 branch is being closed.
Confirmed on x86_64. -O2 fails, -O2 -fno-ipa-modref works.