Bug 69841 - Wrong template instantiation in C++11 on armv7l
Summary: Wrong template instantiation in C++11 on armv7l
Status: RESOLVED DUPLICATE of bug 77728
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 5.3.1
: P3 normal
Target Milestone: ---
Assignee: James Greenhalgh
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-02-16 14:40 UTC by Aleksandar Radovanovic
Modified: 2017-04-26 11:06 UTC (History)
6 users (show)

See Also:
Host:
Target: arm-none-linux-gnueabi
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-02-22 00:00:00


Attachments
Pre-processed source (*.ii) triggering the bug (164.25 KB, application/x-gzip)
2016-02-16 14:40 UTC, Aleksandar Radovanovic
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Aleksandar Radovanovic 2016-02-16 14:40:39 UTC
Created attachment 37706 [details]
Pre-processed source (*.ii) triggering the bug

The two attached source files both instantiate a same std::map<F, A>. However, when compiled with -std=gnu++11, code emitted for 

std::_Rb_tree_iterator<...> 
std::_Rb_tree<...>::_M_emplace_hint_unique<...>
(std::_Rb_tree_const_iterator<std::pair<F const, A> >, std::piecewise_construct_t const&, std::tuple<F&&>&&, std::tuple<>&&)

differs in the two resulting object files:

_ZNSt8_Rb_treeI1FSt4pairIKS0_1AESt10_Select1stIS4_ESt4lessIS0_ESaIS4_EE22_M_emplace_hint_uniqueIJRKSt21piecewise_construct_tSt5tupleIJOS0_EESF_IJEEEEESt17_Rb_tree_iteratorIS4_ESt23_Rb_tree_const_iteratorIS4_EDpOT_:
     .fnstart
-.LFB1874:
-    @ args = 4, pretend = 0, frame = 8
+.LFB1860:
+    @ args = 8, pretend = 0, frame = 8
     @ frame_needed = 0, uses_anonymous_args = 0
     strd    r4, [sp, #-36]!
     .save {r4, r5, r6, r7, r8, r9, r10, fp, lr}
-    mov    r5, r3
     strd   r6, [sp, #8]
     mov    r6, r0
     mov    r0, #32
     strd   r8, [sp, #16]
     add    r9, r6, #4
     strd   r10, [sp, #24]
-    mov    r10, r1
+    mov    r10, r2
     str    lr, [sp, #32]
     .pad #12
     sub    sp, sp, #12
+    ldr    r5, [sp, #48]
     bl     _Znwj
-    ldr    r3, [r5]
     mov    r4, r0
     mov    r1, #0
     mov    r0, #0
     cmp    r9, r10
+    ldr    r3, [r5]
     add    fp, r4, #16
     ldr    r7, [r3]
     str    r7, [r4, #16]
     strd   r0, [r4, #24]


Namely, the layout of call arguments seems to differ. Linking the two together results in one of the calls to _M_emplace_hint_unique in the target binary having mismatched arguments and execution causes a SEGV.

Tested on GCC 5.2.1 and 5.3.1, as shipped with openSUSE Tumbleweed, as well as vanilla 5.3.0 compiled from sources.

System type is armv7hl-suse-linux-gnueabi

gcc -v:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/armv7hl-suse-linux-gnueabi/5/lto-wrapper
Target: armv7hl-suse-linux-gnueabi
Configured with: ../configure --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib --enable-languages=c,c++,objc,fortran,obj-c++,java,go --enable-checking=release --with-gxx-include-dir=/usr/include/c++/5 --enable-ssp --disable-libssp --disable-libvtv --disable-plugin --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --with-slibdir=/lib --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-version-specific-runtime-libs --enable-linker-build-id --enable-linux-futex --program-suffix=-5 --without-system-libunwind --with-arch=armv7-a --with-tune=cortex-a15 --with-float=hard --with-abi=aapcs-linux --with-fpu=vfpv3-d16 --disable-sjlj-exceptions --build=armv7hl-suse-linux-gnueabi --host=armv7hl-suse-linux-gnueabi
Thread model: posix
gcc version 5.3.1 20151207 [gcc-5-branch revision 231355] (SUSE Linux)

Steps to compile / reproduce:
g++ -O2 -Wall -std=gnu++11 -c f1.cpp
g++ -O2 -Wall -std=gnu++11 -c f2.cpp
g++ -O2 -Wall -std=gnu++11 -o f f1.o f2.o
./f
Segmentation fault (core dumped)

Code works as expected in -O0 or -std=gnu++98

Not sure if specific to arm, but I'm filing initially under 'target'
Comment 1 James Greenhalgh 2016-02-22 17:43:03 UTC
Confirmed, I'm trying to figure out what is going wrong.
Comment 2 James Greenhalgh 2016-02-24 10:54:35 UTC
At the heart of the problem, the compiler has decided that the second parameter to this templated function has an overaligned member (64-byte aligned in f2, 8-byte aligned in f1). This gives different parameter passing rules, and you get the code difference above.

I haven't figured out what causes the alignment to differ between the two TUs, or why the compiler feels it is safe to propagate the alignment information without specializing the function name.

I'll take the bug while I look deeper.
Comment 3 James Greenhalgh 2016-02-25 17:40:45 UTC
I'm still confused by this. After coming out of the front end I checked the DECL_ALIGN for each field of each of the parameters being passed to this function. I see:

----
f1.ii

std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...)  
      (struct _Rb_tree * const this
           (decl alignment: 32),
       struct const_iterator __pos
         Fields:
           _M_node (decl alignment: 32)
           _Rb_tree_const_iterator (decl alignment: 8)
           value_type (decl alignment: 8)
           reference (decl alignment: 32)
           pointer (decl alignment: 32)
           iterator (decl alignment: 8)
           iterator_category (decl alignment: 8)
           difference_type (decl alignment: 32)
           _Self (decl alignment: 8)
           _Base_ptr (decl alignment: 32)
           _Link_type (decl alignment: 32)
           (decl alignment: 32, max field alignment: 32),
       const struct piecewise_construct_t & __args#0
           (decl alignment: 32),
       struct tuple & __args#1
           (decl alignment: 32),
       struct tuple & __args#2
           (decl alignment: 32))

f2.ii

std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) 
      (struct _Rb_tree * const this
           (decl alignment: 32),
       struct const_iterator __pos
         Fields:
           _M_node (decl alignment: 32)
           _Rb_tree_const_iterator (decl alignment: 8)
           value_type (decl alignment: 64)
           reference (decl alignment: 32)
           pointer (decl alignment: 32)
           iterator (decl alignment: 32)
           iterator_category (decl alignment: 8)
           difference_type (decl alignment: 32)
           _Self (decl alignment: 8)
           _Base_ptr (decl alignment: 32)
           _Link_type (decl alignment: 32)
           (decl alignment: 32, max field alignment: 64),
       const struct piecewise_construct_t & __args#0
           (decl alignment: 32),
       struct tuple & __args#1
           (decl alignment: 32),
       struct tuple & __args#2
           (decl alignment: 32))
---

That is to say, after gimplification we've already decided that the alignment of the value_type field of the std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator parameter to std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique in f2.ii is 64, whereas in f1.ii we don't have any extra alignment information.

I know nothing about the C++ front-end and how we could end up in this situation. I can understand why, given this, we would generate the code we do for ARM.
Comment 4 James Greenhalgh 2016-02-26 18:32:24 UTC
Goes away on trunk after r223301

Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Mon May 18 17:14:11 2015 +0000

    	DR 1391
    	* pt.c (type_unification_real): Check convertibility here.
    	(unify_one_argument): Not here.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223301 

After which the DECL_ALIGN in both TUs is 64, fixing the bug.
Comment 5 James Greenhalgh 2016-03-09 12:01:37 UTC
I don't know enough about the C++ standard to know whether this patch is reasonable to backport to GCC 5. Jason, do you have an opinion?
Comment 6 James Greenhalgh 2016-04-11 10:29:34 UTC
*ping*
Comment 7 Jason Merrill 2016-04-11 15:00:20 UTC
(In reply to James Greenhalgh from comment #5)
> I don't know enough about the C++ standard to know whether this patch is
> reasonable to backport to GCC 5. Jason, do you have an opinion?

I'd be pretty nervous about packporting that patch, as changes to that behavior tend to have unexpected side-effects.  And it seems likely to have just made this bug latent, rather than actually fixed it.
Comment 8 Richard Earnshaw 2017-04-26 11:06:50 UTC
Looks like a dup of 77728.  At O1 or lower we get the new ABI change warning with a trunk compiler.  Presumably at higher levels of optimization the prolematic code gets optimized away.

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