Bug 5174 - Uncatchable C++ exceptions with NPTL on ARM and -fomit-frame-pointer
Summary: Uncatchable C++ exceptions with NPTL on ARM and -fomit-frame-pointer
Status: NEW
Alias: None
Product: uClibc
Classification: Unclassified
Component: Threads (show other bugs)
Version: unspecified
Hardware: PC Linux
: P5 major
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-04 16:08 UTC by Ignacy Gawędzki
Modified: 2014-10-20 13:44 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:


Attachments
The source code (10.00 KB, application/x-tar)
2012-05-04 16:08 UTC, Ignacy Gawędzki
Details
Buildroot's .config (23.64 KB, text/plain)
2012-05-04 20:31 UTC, Ignacy Gawędzki
Details
uClibc's .config (6.03 KB, text/plain)
2012-05-08 18:56 UTC, Ignacy Gawędzki
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ignacy Gawędzki 2012-05-04 16:08:31 UTC
Created attachment 4322 [details]
The source code

Some exceptions seem to be uncatchable when running a dynamically linked binary with libpthread and uClibc with NPTL support.

The binary must be composed of two compilation units which source files are in the attached tarball.  The whole executable must be compiled in the following way:

  arm-linux-g++ -fomit-frame-pointer -o ex-bug ex-bug.cc ex-bug1.cc -lpthread

Apparently it doesn't matter which version of GCC/uClibc/binutils it has been compiled with.  In any case, when run in an environment with uClibc with NPTL support, it crashes with signal SIGABRT instead of quitting silently.

Note that this problem doesn't appear when either:

 . uClibc in the runtime environment is compiled with linuxthreads instead of NPTL.
 . the executable is not linked with libpthread
 . the executable is linked statically
 . the executable is compiled without -fomit-frame-pointer
 . the code is not split in two separate compilation units
 . the instance of Foo is not created the local scope of throw_something()
 . the destructor of Foo can be optimized-out by GCC (hence the "volatile" qualifier)
 . the call to throw_something() in main() is not in a try/catch block
 . the catch doesn't intend to catch the thrown exception

I've just tested this on uClibc snapshot and buildroot 4205dbd9f665556cc56a36c0e11a5f845c73a57a, but have tested it before in earlier uClibc version that offered support for NPTL and some earlier buildroot commits.
Comment 1 Bernhard Reutner-Fischer 2012-05-04 19:21:13 UTC
.config please? Anything different with -O0?
Comment 2 Ignacy Gawędzki 2012-05-04 20:31:28 UTC
Created attachment 4328 [details]
Buildroot's .config
Comment 3 Ignacy Gawędzki 2012-05-04 20:32:29 UTC
(In reply to comment #1)
> .config please? Anything different with -O0?

The -O0 option means not -fomit-frame-pointer, so it works as expected.
Comment 4 Ignacy Gawędzki 2012-05-08 10:17:01 UTC
Did anyone manage to reproduce the problem or am I the only one?
Comment 5 Bernhard Reutner-Fischer 2012-05-08 18:26:45 UTC
(In reply to comment #4)
> Did anyone manage to reproduce the problem or am I the only one?

Can you provide a gdb "bt f" with debug symbols turned on in the build, please?

PS: I ment uClibc .config, not buildroot's config.
PPS: sounds like a dup of #259
Comment 6 Ignacy Gawędzki 2012-05-08 18:56:04 UTC
Created attachment 4346 [details]
uClibc's .config
Comment 7 Ignacy Gawędzki 2012-05-09 08:34:31 UTC
(In reply to comment #5)
> (In reply to comment #4)
> > Did anyone manage to reproduce the problem or am I the only one?
> 
> Can you provide a gdb "bt f" with debug symbols turned on in the build, please?

I'm having a hard time compiling buildroot with debug options.  If I activate DODEBUG, DOASSERTS, SUPPORT_LD_DEBUG and SUPPORT_LD_DEBUG_EARLY in uClibc's configuration, I get the following error:

/opt/users/ig/code/buildroot-git/output/host/usr/bin/arm-unknown-linux-uclibcgnueabi-gcc -Wl,-EL -shared -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,relro -Wl,-z,now -Wl,-z,defs   -Wl,-init,__uClibc_init  -Wl,-soname=libc.so.0 -nostdlib -o lib/libuClibc-0.9.34-git.so  -Wl,--whole-archive libc/libc_so.a -Wl,--no-whole-archive ./lib/interp.os ./lib/ld-uClibc.so.0 ./lib/uclibc_nonshared.a /opt/users/ig/code/buildroot-git/output/host/usr/lib/gcc/arm-unknown-linux-uclibcgnueabi/4.7.0/libgcc.a 
libc/libc_so.a(lockf.os): In function `__GI_lockf':
/opt/users/ig/code/buildroot-git/output/toolchain/uClibc/libc/misc/file/lockf.c:73: undefined reference to `_Unwind_Resume'
libc/libc_so.a(lockf.os):(.ARM.extab+0x0): undefined reference to `__gcc_personality_v0'
collect2: error: ld returned 1 exit status

Nevertheless, I'm able to compile with debug in Buildroot's configuration only.  Here's the backtrace:

Program received signal SIGABRT, Aborted.
0x4091daf8 in raise ()
   from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
(gdb) bt
#0  0x4091daf8 in raise ()
   from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
#1  0x40918ca0 in abort ()
   from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
#2  0x408d976c in unwind_phase2 (ucbp=0x11178, vrs=0x4092c1c4)
    at /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/unwind-arm-common.inc:289
#3  0x408d98e8 in __gnu_Unwind_Resume (ucbp=0x11178, entry_vrs=0x40800054)
    at /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/unwind-arm-common.inc:502
#4  0x408da384 in ___Unwind_Resume ()
    at /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/config/arm/libunwind.S:345
#5  0x4080ef74 in ?? ()
   from /opt/users/ig/code/buildroot-git/output/target/lib/ld-uClibc.so.0
#6  0x4080ef74 in ?? ()
   from /opt/users/ig/code/buildroot-git/output/target/lib/ld-uClibc.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Comment 8 Bernhard Reutner-Fischer 2013-01-16 12:08:43 UTC
(In reply to comment #7)
> (In reply to comment #5)
> > (In reply to comment #4)
> > > Did anyone manage to reproduce the problem or am I the only one?
> > 
> > Can you provide a gdb "bt f" with debug symbols turned on in the build, please?
> 
> I'm having a hard time compiling buildroot with debug options.  If I activate
> DODEBUG, DOASSERTS, SUPPORT_LD_DEBUG and SUPPORT_LD_DEBUG_EARLY in uClibc's
> configuration, I get the following error:
> 
> /opt/users/ig/code/buildroot-git/output/host/usr/bin/arm-unknown-linux-uclibcgnueabi-gcc
> -Wl,-EL -shared -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,relro
> -Wl,-z,now -Wl,-z,defs   -Wl,-init,__uClibc_init  -Wl,-soname=libc.so.0
> -nostdlib -o lib/libuClibc-0.9.34-git.so  -Wl,--whole-archive libc/libc_so.a
> -Wl,--no-whole-archive ./lib/interp.os ./lib/ld-uClibc.so.0
> ./lib/uclibc_nonshared.a
> /opt/users/ig/code/buildroot-git/output/host/usr/lib/gcc/arm-unknown-linux-uclibcgnueabi/4.7.0/libgcc.a 
> libc/libc_so.a(lockf.os): In function `__GI_lockf':
> /opt/users/ig/code/buildroot-git/output/toolchain/uClibc/libc/misc/file/lockf.c:73:
> undefined reference to `_Unwind_Resume'
> libc/libc_so.a(lockf.os):(.ARM.extab+0x0): undefined reference to
> `__gcc_personality_v0'
> collect2: error: ld returned 1 exit status

This GCC bug was fixed already.
See http://gcc.gnu.org/PR51117

> 
> Nevertheless, I'm able to compile with debug in Buildroot's configuration only.
>  Here's the backtrace:
> 
> Program received signal SIGABRT, Aborted.
> 0x4091daf8 in raise ()
>    from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
> (gdb) bt
> #0  0x4091daf8 in raise ()
>    from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
> #1  0x40918ca0 in abort ()
>    from /opt/users/ig/code/buildroot-git/output/target/lib/libc.so.0
> #2  0x408d976c in unwind_phase2 (ucbp=0x11178, vrs=0x4092c1c4)
>     at
> /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/unwind-arm-common.inc:289
> #3  0x408d98e8 in __gnu_Unwind_Resume (ucbp=0x11178, entry_vrs=0x40800054)
>     at
> /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/unwind-arm-common.inc:502
> #4  0x408da384 in ___Unwind_Resume ()
>     at
> /opt/users/ig/code/buildroot-git/output/toolchain/gcc-4.7.0/libgcc/config/arm/libunwind.S:345
> #5  0x4080ef74 in ?? ()
>    from /opt/users/ig/code/buildroot-git/output/target/lib/ld-uClibc.so.0
> #6  0x4080ef74 in ?? ()
>    from /opt/users/ig/code/buildroot-git/output/target/lib/ld-uClibc.so.0
> Backtrace stopped: previous frame identical to this frame (corrupt stack?)
Comment 9 busybox 2014-01-29 16:33:09 UTC
(In reply to comment #8)
> (In reply to comment #7)
> > (In reply to comment #5)
> > 
> > I'm having a hard time compiling buildroot with debug options.  If I activate
> > DODEBUG, DOASSERTS, SUPPORT_LD_DEBUG and SUPPORT_LD_DEBUG_EARLY in uClibc's
> > configuration, I get the following error:
> > 
> > /opt/users/ig/code/buildroot-git/output/host/usr/bin/arm-unknown-linux-uclibcgnueabi-gcc
> > -Wl,-EL -shared -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc -Wl,-z,relro
> > -Wl,-z,now -Wl,-z,defs   -Wl,-init,__uClibc_init  -Wl,-soname=libc.so.0
> > -nostdlib -o lib/libuClibc-0.9.34-git.so  -Wl,--whole-archive libc/libc_so.a
> > -Wl,--no-whole-archive ./lib/interp.os ./lib/ld-uClibc.so.0
> > ./lib/uclibc_nonshared.a
> > /opt/users/ig/code/buildroot-git/output/host/usr/lib/gcc/arm-unknown-linux-uclibcgnueabi/4.7.0/libgcc.a 
> > libc/libc_so.a(lockf.os): In function `__GI_lockf':
> > /opt/users/ig/code/buildroot-git/output/toolchain/uClibc/libc/misc/file/lockf.c:73:
> > undefined reference to `_Unwind_Resume'
> > libc/libc_so.a(lockf.os):(.ARM.extab+0x0): undefined reference to
> > `__gcc_personality_v0'
> > collect2: error: ld returned 1 exit status
> 
> This GCC bug was fixed already.
> See http://gcc.gnu.org/PR51117

Sorry, I think the mentioned GCC bug is unrelated.

/opt/users/ig/code/buildroot-git/output/toolchain/uClibc/libc/misc/file/lockf.c:73: undefined reference to `_Unwind_Resume'

When compiling buildroot 2013.11 with uclibc's DODEBUG and buildroot's BR2_PREFER_STATIC_LIB I get the same error. Without this DODEBUG uclibc-option it works fine. No matter if I use gcc 4.7.3 or 4.8.2.

But I found a fix from January 2013 that you committed for this problem in uclibc. It is about a missing dependency to libgcc_eh. When I apply this patch then I can compile without this linker error even when using DODEBUG.

Sadly this fix is not yet available in the current uclibc release (0.9.33.2).

commit: http://git.uclibc.org/uClibc/commit/?id=8d31a6e50db423b89082b64a3250eec1b94a7456
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

with -O0 we (e.g. lockf) might end up with references to
_Unwind_Resume, so pull in gcc_eh in this case..

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
---
 Rules.mak              |    4 ++++
 libc/misc/file/lockf.c |    5 +----
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Rules.mak b/Rules.mak
index 8943fbf..9d621b5 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -804,6 +804,10 @@ ASFLAGS = $(ASFLAG_--noexecstack)
 
 LIBGCC_CFLAGS ?= $(CFLAGS) $(CPU_CFLAGS-y)
 $(eval $(call cache-output-var,LIBGCC,$(CC) $(LIBGCC_CFLAGS) -print-libgcc-file-name))
+$(eval $(call cache-output-var,LIBGCC_EH,$(CC) $(LIBGCC_CFLAGS) -print-file-name=libgcc_eh.a))
+# with -O0 we (e.g. lockf) might end up with references to
+# _Unwind_Resume, so pull in gcc_eh in this case..
+LIBGCC += $(if $(DODEBUG),$(LIBGCC_EH))
 LIBGCC_DIR:=$(dir $(LIBGCC))
 
 # moved from libpthread/linuxthreads
diff --git a/libc/misc/file/lockf.c b/libc/misc/file/lockf.c
index 4e398cd..56b3aac 100644
--- a/libc/misc/file/lockf.c
+++ b/libc/misc/file/lockf.c
@@ -16,15 +16,12 @@
    see <http://www.gnu.org/licenses/>.  */
 
 #include <features.h>
-
 #include <sys/types.h>
-#include <unistd.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <errno.h>
 #include <string.h>
 
-
-
 /* lockf is a simplified interface to fcntl's locking facilities.  */
 
 int lockf (int fd, int cmd, off_t len)
Comment 10 Ralph Siemsen 2014-10-15 19:42:59 UTC
I've just stumbled across the same bug, thought it took several days to narrow it down and eventually find this bug report.

The symptoms are practically identical:
- cross-compiling for ARM target
- executable is linked with -lpthread (even when it doesn't use threads)
- throw() occurs in a subroutine, not in the try/catch block.
- the subroutine allocates some local object too (likely avoids inlining)
- compile with -O1 or higher, which enables -fomit-frame-pointer.
- uClibc-0.9.33.2, NPTL

Differences:
- I can trigger the SIGABRT in a single compilation unit.
- The catch block can match the thrown exception, or it can be "..." (both fail)
- I'm targeting cortex A9 rather than A8.
- I've used buildroot 2013.08 and also 2014.08, both failed.
- External toolchains from Codesourcery do not have this problem.

Here's my test program. It crashes with SIGABRT if the above conditions are met. If compiled with -O0 or -fno-omit-frame-pointer then it runs fine and prints "CATCH" as expected.

/*
 * arm-linux-gcc -O1 -Wall -o cpptest cpptest.cpp -lpthread
 */
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

void subroutine(void) throw(std::out_of_range)
{
        std::ostringstream strStream;
        throw std::out_of_range("foobar");
}

int main()
{
        try
        {
                subroutine();
        }
        catch (...)  // catch (std::out_of_range) also fails
        {
                std::cerr << "CATCH" << std::endl;
        }
        return 0;
}


Please let me know if I can provide any more debug info.

I'm also testing the patch from comment 9, however so far it does not seem to fix the issue for me.
Comment 11 Ralph Siemsen 2014-10-15 19:46:38 UTC
Minor typo:

> /*
>  * arm-linux-gcc -O1 -Wall -o cpptest cpptest.cpp -lpthread
>  */

should of course be arm-linux-g++ not gcc
Comment 12 Ralph Siemsen 2014-10-15 20:28:36 UTC
I also decided to try today's uClibc snapshot, which should include the patch, but after a full rebuild, the SIGABRT behaviour persists.