LibreOffice 4.2 or newer fails to build in a clean build environment on Linux x86-32 with gcc 4.9.0, 4.9.1, and 4.9.2. However, the build succeeds on an otherwise identical x86-64 system, and it also succeeds with gcc 4.8.2 (on x86-32 and x86-64). The build also succeeds with clang 3.4 (on x86-32 and x86-64). The same errors appear in two places (svx and dbaccess), both times referring to classes from toolkit/source/helper/listenermultiplexer.cxx, which compiled fine without warnings. Steps to reproduce on x86 NOT x86-64: 1. $ git clone git://anongit.freedesktop.org/libreoffice/core 2. $ git checkout libreoffice-4-4-0 (optional, master fails with same errors) 3. $ apt-get build-dep libreoffice ( also lo_usefull Shell Script if missing dep) 4 ./autogen.sh && make Build log: /src/libreoffice-4.2.3.3/workdir/CxxObject/svx/source/fmcomp/fmgridif.o: In function `FmXGridControl::createPeer(com::sun::star::uno::Reference<com::sun::star::awt::XToolkit> const&, com::sun::star::uno::Reference<com::sun::star::awt::XWindowPeer> const&)': fmgridif.cxx:(.text+0x7f5a): undefined reference to `non-virtual thunk to WindowListenerMultiplexer::acquire()' fmgridif.cxx:(.text+0x7fb5): undefined reference to `non-virtual thunk to FocusListenerMultiplexer::acquire()' fmgridif.cxx:(.text+0x8010): undefined reference to `non-virtual thunk to KeyListenerMultiplexer::acquire()' fmgridif.cxx:(.text+0x806b): undefined reference to `non-virtual thunk to MouseListenerMultiplexer::acquire()' fmgridif.cxx:(.text+0x80c6): undefined reference to `non-virtual thunk to MouseMotionListenerMultiplexer::acquire()' fmgridif.cxx:(.text+0x8121): undefined reference to `non-virtual thunk to PaintListenerMultiplexer::acquire()' collect2: error: ld returned 1 exit status /src/libreoffice-4.2.3.3/svx/Library_svxcore.mk:20: recipe for target '/src/libreoffice-4.2.3.3/instdir/program/libsvxcorelo.so' failed make[1]: *** [/src/libreoffice-4.2.3.3/instdir/program/libsvxcorelo.so] Error 1 /src/libreoffice-4.2.3.3/workdir/CxxObject/dbaccess/source/ui/uno/ColumnControl.o: In function `.L362': ColumnControl.cxx:(.text+0x1588): undefined reference to `non-virtual thunk to WindowListenerMultiplexer::acquire()' ColumnControl.cxx:(.text+0x15d6): undefined reference to `non-virtual thunk to FocusListenerMultiplexer::acquire()' ColumnControl.cxx:(.text+0x1624): undefined reference to `non-virtual thunk to KeyListenerMultiplexer::acquire()' ColumnControl.cxx:(.text+0x1672): undefined reference to `non-virtual thunk to MouseListenerMultiplexer::acquire()' ColumnControl.cxx:(.text+0x16c0): undefined reference to `non-virtual thunk to MouseMotionListenerMultiplexer::acquire()' ColumnControl.cxx:(.text+0x170e): undefined reference to `non-virtual thunk to PaintListenerMultiplexer::acquire()' collect2: error: ld returned 1 exit status /src/libreoffice-4.2.3.3/dbaccess/Library_dbu.mk:10: recipe for target '/src/libreoffice-4.2.3.3/instdir/program/libdbulo.so' failed make[1]: *** [/src/libreoffice-4.2.3.3/instdir/program/libdbulo.so] Error 1
Please try to narrow down the issue and attach prepossessed testcases (of fmgridif.cxx and ColumnControl.cxx for a start). Also find out where the `non-virtual thunk to WindowListenerMultiplexer::acquire()' comes from in a successful build. (add -Wl,--no-demangle to the link command, and search object files for the unmangled symbol.) Nobody will git clone LibreOffice just to reproduce the problem.
(In reply to Markus Trippelsdorf from comment #1) > Please try to narrow down the issue and attach prepossessed testcases > (of fmgridif.cxx and ColumnControl.cxx for a start). > Also find out where the `non-virtual thunk to > WindowListenerMultiplexer::acquire()' comes from in a successful build. > (add -Wl,--no-demangle to the link command, and search object files > for the unmangled symbol.) Sorry, this should read: Please try to narrow down the issue and attach preprocessed testcases (of fmgridif.cxx and ColumnControl.cxx for a start). Also find out where the `non-virtual thunk to WindowListenerMultiplexer::acquire()' comes from in a successful build. (add -Wl,--no-demangle to the link command, and search object files for the mangled symbol.)
I can reproduce this, but unfortunately I don't have minimalistic test case yet. As a workaround removing -fvisibility-inlines-hidden from the build flags, makes things work in the libreoffice. What is involved / happening is: The non-virtual thunks are in a DSO, but marked hidden. This is caused by -fvisibility-inlines-hidden. The ::acquire members are virtual, but with inline implementation (no inline marking / attribute though). The class itself is marked __attribute__((visibility("default"))). It appears that the places getting these unresolved symbols are trying to call external symbol, even though it's inline implementation. Apparently optimization flags, code context affects when this happens. The symptoms sounds very much similar to what was in llvm: http://llvm.org/bugs/show_bug.cgi?id=12255
(In reply to Luke from comment #0) > LibreOffice 4.2 or newer fails to build in a clean build environment on > Linux x86-32 with gcc 4.9.0, 4.9.1, and 4.9.2. However, the build succeeds > on an otherwise identical x86-64 system, and it also succeeds with gcc 4.8.2 > (on x86-32 and x86-64). The build also succeeds with clang 3.4 (on x86-32 > and x86-64). > We are seeing this in gentoo on x86_64 with gcc-4.9. See https://bugs.gentoo.org/show_bug.cgi?id=538348 (In reply to Timo Teräs from comment #3) > As a workaround removing -fvisibility-inlines-hidden from the build flags, > makes things work in the libreoffice. What's confusing me is that some of our users are seeing this bug and others are not. This leads me to think maybe its a c++ abi mismatch because we do allow our users to build their systems using any recent version of gcc (and c++ abi emitted by 4.8 is not compatbile with that emitted by 4.9). However, that fact tat removing -fvisibility-inlines-hidden fixes this argues against my suspicion. So why would some of our users it this and others not?
the problem is that with -Os, the inline method WindowListenerMultiplexer::acquire() results in an undefined symbol, whereas with -O2 weak symbols are emitted into the object. can reproduce this with: gcc (GCC) 4.9.2 20141101 (Red Hat 4.9.2-1) the command line parameters for compilation in the build system were: g++ -m32 -fvisibility=hidden -fmessage-length=0 -fno-common -fvisibility-inlines-hidden -fstack-protector-strong -fPIC -std=gnu++11 -ggdb2 -fexceptions -fno-enforce-eh-specs -Os -c /tmp/fmgridif.ii -o /tmp/fmgridif.o the minimal command line parameters to trigger the bug: > g++ -m32 -std=gnu++11 -Os -c /tmp/fmgridif.ii -o /tmp/fmgridif.o > nm --demangle /tmp/fmgridif.o | grep WindowListenerMultiplexer U non-virtual thunk to WindowListenerMultiplexer::acquire() the minimal command line parameters to avoid the bug: > g++ -m32 -std=gnu++11 -O2 -c /tmp/fmgridif.ii -o /tmp/fmgridif.o > nm --demangle /tmp/fmgridif.o | grep WindowListenerMultiplexer 00000000 W WindowListenerMultiplexer::acquire() 00000020 W non-virtual thunk to WindowListenerMultiplexer::acquire()
Created attachment 34780 [details] manually minimized reproducer to reproduce, build with: g++ -m32 -std=gnu++11 -Os -c /tmp/fmgridif.ii -o /tmp/fmgridif.o
markus@x4 tmp % cat fmgridif.ii template <class T> class A { T *p; public: A (T *p1) : p (p1) { p->acquire (); } }; class B { public: virtual void acquire (); }; class D : public B { }; class F : B { int mrContext; }; class WindowListenerMultiplexer : F, public D { void acquire () { acquire (); } }; class C { void createPeer () throw (); WindowListenerMultiplexer maWindowListeners; }; class FmXGridPeer { public: void addWindowListener (A<D>); } a; void C::createPeer () throw () { a.addWindowListener (&maWindowListeners); } markus@x4 tmp % g++ -Os -c fmgridif.ii && nm --demangle fmgridif.o | grep WindowListenerMultiplexer U non-virtual thunk to WindowListenerMultiplexer::acquire() markus@x4 tmp % g++ -O2 -c fmgridif.ii && nm --demangle fmgridif.o | grep WindowListenerMultiplexer 0000000000000000 W WindowListenerMultiplexer::acquire() 0000000000000010 W non-virtual thunk to WindowListenerMultiplexer::acquire() Not sure if the devirtualization is valid. Honza?
Also happens with gcc-5 when linking two different LibreOffice libraries. (libscfiltlo.so and libooxlo.so) The undefined symbol is: x4 ~ # c++filt _ZThn40_N3utl28OSeekableOutputStreamWrapper7acquireEv non-virtual thunk to utl::OSeekableOutputStreamWrapper::acquire() But the symbol is defined in workdir/CxxObject/unotools/source/streaming/streamwrap.o and adding this object file to the link object file list fixes the problem. So it looks like a LibreOffice issue in this case.
(In reply to Markus Trippelsdorf from comment #8) > Also happens with gcc-5 when linking two different LibreOffice libraries. > (libscfiltlo.so and libooxlo.so) > > The undefined symbol is: > x4 ~ # c++filt _ZThn40_N3utl28OSeekableOutputStreamWrapper7acquireEv > non-virtual thunk to utl::OSeekableOutputStreamWrapper::acquire() interesting ... you are building LO 4.4.1.1 or older? looking at the git log there is this apparent work-around: http://cgit.freedesktop.org/libreoffice/core/commit/?id=8bb0446974282b32d06cdbd35af83f91e033b4af not sure if it's the same bug... in case this is triggered by some sort of de-virtualization new in GCC5 then i guess it is LO's fault because the acquire() / release() was not dll-exported. i will push that to the libreoffice-4-3 release branch to get it into 4.3.7. (i've only tried to build current master, which works fine now with workaround for the bug from the description)
(In reply to Michael Stahl from comment #9) > interesting ... you are building LO 4.4.1.1 or older? 4.4.1.2
GCC 4.9.3 has been released.
Markus, the devirtualization seems valid to me. You are supposed to link with the implementaiton of the class. It is possible to overwrite this by manually setting the visibility. We however end up with funny code in optimized dump: <bb 2>: _3 = this_2(D)->D.2399.D.2325._vptr.B; _4 = *_3; PROF_6 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_6 == acquire) goto <bb 3>; else goto <bb 18>; <bb 3>: PROF_10 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_10 == acquire) goto <bb 4>; else goto <bb 17>; <bb 4>: PROF_14 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_14 == acquire) goto <bb 5>; else goto <bb 16>; <bb 5>: PROF_18 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_18 == acquire) goto <bb 6>; else goto <bb 15>; <bb 6>: PROF_22 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_22 == acquire) goto <bb 7>; else goto <bb 14>; <bb 7>: PROF_26 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_26 == acquire) goto <bb 8>; else goto <bb 13>; <bb 8>: PROF_30 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_30 == acquire) goto <bb 9>; else goto <bb 12>; <bb 9>: PROF_34 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_34 == acquire) goto <bb 10>; else goto <bb 11>; <bb 10>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 11>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 12>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 13>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 14>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 15>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 16>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 17>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 19>; <bb 18>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] <bb 19>: return; } this is result of recursive inlining over the devirtualized call that sort of seem legit even though it is bit of overkill. RTL optimizers simplify this to: _ZN25WindowListenerMultiplexer7acquireEv: .LFB1: .cfi_startproc movq (%rdi), %rax jmp *(%rax) .cfi_endproc .LFE1: RIchi, I think PRE is supposed to optimize this?
On Thu, 3 Dec 2015, hubicka at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64812 > > Jan Hubicka <hubicka at gcc dot gnu.org> changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > CC| |rguenther at suse dot de > > --- Comment #12 from Jan Hubicka <hubicka at gcc dot gnu.org> --- > Markus, > the devirtualization seems valid to me. You are supposed to link with the > implementaiton of the class. It is possible to overwrite this by manually > setting the visibility. > > We however end up with funny code in optimized dump: > > <bb 2>: > _3 = this_2(D)->D.2399.D.2325._vptr.B; > _4 = *_3; > PROF_6 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_6 == acquire) > goto <bb 3>; > else > goto <bb 18>; > > <bb 3>: > PROF_10 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_10 == acquire) > goto <bb 4>; > else > goto <bb 17>; > > <bb 4>: > PROF_14 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_14 == acquire) > goto <bb 5>; > else > goto <bb 16>; > > <bb 5>: > PROF_18 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_18 == acquire) > goto <bb 6>; > else > goto <bb 15>; > > <bb 6>: > PROF_22 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_22 == acquire) > goto <bb 7>; > else > goto <bb 14>; > > <bb 7>: > PROF_26 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_26 == acquire) > goto <bb 8>; > else > goto <bb 13>; > <bb 8>: > PROF_30 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_30 == acquire) > goto <bb 9>; > else > goto <bb 12>; > > <bb 9>: > PROF_34 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct > WindowListenerMultiplexer)this_2(D)->0); > if (PROF_34 == acquire) > goto <bb 10>; > else > goto <bb 11>; > > <bb 10>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 11>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 12>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 13>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 14>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 15>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 16>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 17>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > goto <bb 19>; > > <bb 18>: > OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); > [tail call] > > <bb 19>: > return; > > } > > this is result of recursive inlining over the devirtualized call that sort of > seem legit even though it is bit of overkill. > > RTL optimizers simplify this to: > > _ZN25WindowListenerMultiplexer7acquireEv: > .LFB1: > .cfi_startproc > movq (%rdi), %rax > jmp *(%rax) > .cfi_endproc > .LFE1: > > RIchi, I think PRE is supposed to optimize this? Ah, for some reason OBJ_TYPE_REF is a GENERIC tree (single RHS) and SCCVN doesn't handle it at all. I have a patch which will produce <bb 2>: _3 = this_2(D)->D.2399.D.2325._vptr.B; _4 = *_3; PROF_6 = [obj_type_ref] OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0); if (PROF_6 == acquire) goto <bb 3>; else goto <bb 4>; <bb 3>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] goto <bb 5>; <bb 4>: OBJ_TYPE_REF(_4;(struct WindowListenerMultiplexer)this_2(D)->0) (this_2(D)); [tail call] thus it also misses to "propagate" acquire into the tailcall. That could be fixed as well but only in two steps, first replacing the OBJ_TYPE_REF in the call with PROF_6 ("CSE" it) and later DOM might propagate the equivalence.
(In reply to Jan Hubicka from comment #12) > the devirtualization seems valid to me. You are supposed to link with the > implementaiton of the class. It is possible to overwrite this by manually > setting the visibility. actual code in LibreOffice *did* link with the implementation of the class - there were 2 libraries involved, "toolkit" contained the implementation of ListenerMultiplexerBase and "svxcore" linked against it; ListenerMultiplexerBase has __attribute__ ((visibility("default"))) so its member functions should be exported. the member functions in question (acquire and release) are inline, and i was assuming that it's ok then that they are not exported from the library containing the impl. of the class, but if you say that linking needs to happen anyway then maybe the bug is that the inline functions are not exported from the "toolkit" library by GCC.
Looks rather UNCONFIRMED (libreoffice bug?) to me. Unclear status on trunk. Keeping P3.
GCC 4.9 branch is being closed
GCC 5 branch has been closed, assuming to be fixed in GCC 6 and later, if that is not the case, please reopen with details with what supported versions it can be reproduced and how.