Segmentation fault during dynamic_cast

2,119 views
Skip to first unread message

Marcel Smit

unread,
Mar 24, 2011, 8:46:40 AM3/24/11
to android-ndk

Hi all,

I encounter a segmentation fault during a dynamic_cast in combination
with the use of shared libraries. There's no problem when everything
is
build statically.

Specifically the problem occurs when having a shared library which
uses
rtti/exceptions and which links (statically as that is the only option
currently) libsup++ that is linked to an executable which also uses
rtti/exceptions.
Inspection shows this executable does not statically link the libsup++
code but rather dynamically links the libsup++ code linked into the
shared lib.
The crash occurs on a dynamic_cast<> in the code of the main
executable.
dynamic_cast<>'s in the shared library code do not crash.

Version information:
Android emulator version: Android 9
NDK version: r5b
Toolchain version : 9

Below the reproducer code and gcc command lines with which I've
(cross)built this reproducer.
After that, the output of the reproducer and logcat are shown.

Since the same construction is used in our project code very often, it
is a pretty big issue for us.

Hopefully somebody is able to reproduce this on his own system and can
confirm this is an issue.

Thanks for your help.

Marcel Smit


I've created the following reproducer code:

Library (cast_lib.cpp) :

/**
* Reproducer of the dynamic_cast crash on Android 9, using the NDK
r5b
* toolchain
*/

#include <stdexcept>

namespace
{
struct Base
{
virtual ~Base()
{}
};

struct Derived : public Base
{
int value;
};

struct Another : public Base
{
int x;
int y;
};
}

void test()
{
::printf ("***** starting test in shared lib\n");

::printf (">>> dynamic_cast\n");
Derived d;
d.value = 24;
Base * b1 = &d;
Derived * d1 = dynamic_cast<Derived*>(b1);
if (d1 == 0)
{
::printf ("dynamic_cast returns null, expected value\n");
}
::printf ("<<< dynamic_cast\n");

::printf (">>> dynamic_cast: value check\n");
d1->value = 42;
if (d.value != 42)
{
::printf ("Wrong value after dynamic_cast, expected %d, got %d
\n", 42, d.value);
}
::printf ("<<< dynamic_cast: value check\n");

::printf (">>> dynamic_cast: invalid cast\n");
Another a;
Base * b2 = &a;
Derived * d2 = dynamic_cast<Derived*>(b2);
if (d2 != 0)
{
::printf ("dynamic_cast should return nill\n");
}
::printf ("<<< dynamic_cast: invalid cast\n");


::printf ("***** finished test in shared lib\n");
}
/*************************************************************/


Main (cast.cpp):

/**
* Reproducer of the dynamic_cast crash on Android 9, using the NDK r5
* toolchain
*/

#include <stdexcept>

namespace
{
struct Base2
{
virtual ~Base2()
{}
};

struct Derived2 : public Base2
{
int value;
};
}

extern void test();

int main(int , char **)
{
int status = 0;

test ();

::printf ("***** starting test in main\n");

// Make sure dynamic cast through pointers work ...
Derived2 d;
d.value = 24;
Base2 * b1 = &d;
Derived2 * d1 = dynamic_cast<Derived2*>(b1);
if (d1 == 0)
{
status = 1;
::printf ("dynamic_cast returns null, expected value\n");
}
::printf ("***** finished test in main\n");

return status;
}

/*************************************************************/

The following commands are used to build the library:

arm-linux-androideabi-g++ -W -Wall -Wpointer-arith -ggdb
-Wa,--noexecstack -O0 -pipe -D_REENTRANT -D_GNU_SOURCE
-ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__
-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -Wno-psabi -
march=armv5te
-mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer
-fno-strict-aliasing -finline-limit=64 -fexceptions -frtti -I.. -c -
fPIC
-o cast_lib.o cast_lib.cpp

arm-linux-androideabi-g++ -Wl,-O3 -D_REENTRANT -D_GNU_SOURCE
-ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__
-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -Wno-psabi -
march=armv5te
-mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer
-fno-strict-aliasing -finline-limit=64 -fexceptions -frtti -I.. -
shared
-Wl,-h -Wl,libcast.so -o libcast.so cast_lib.o -Wl,-rpath-link,`pwd`
-Wl,-E -lsupc++ -lstdc++ -Wl,--gc-sections -Wl,-z,nocopyreloc
-Wl,--no-undefined -Wl,-z,noexecstack -L../lib -L. -L../lib -ldl


The following command is used to build the program:

arm-linux-androideabi-g++ -W -Wall -Wpointer-arith -ggdb
-Wa,--noexecstack -O0 -frtti -pipe -D_REENTRANT -D_GNU_SOURCE -fpic
-ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__
-D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -Wno-psabi -
march=armv5te
-mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer
-fno-strict-aliasing -finline-limit=64 -fexceptions -I.. -fPIC -L.
-lcast -Wl,-E -lsupc++ -lstdc++ -Wl,--gc-sections -Wl,-z,nocopyreloc
-Wl,--no-undefined -Wl,-z,noexecstack -ldl -o cast cast.cpp

When running on an emulator, the following output is generated:

[xxxxx@fc14androidr9 platform-tools]$ ./adb shell
# logcat -c
# LD_LIBRARY_PATH=/data/tests;export LD_LIBRARY_PATH
# cd /data/tests
# ./cast
***** starting test in shared lib
>>> dynamic_cast
<<< dynamic_cast
>>> dynamic_cast: value check
<<< dynamic_cast: value check
>>> dynamic_cast: invalid cast
<<< dynamic_cast: invalid cast
***** finished test in shared lib
***** starting test in main
[1] + Stopped (signal) ./cast
#
[1] Segmentation fault ./cast
# logcat
I/DEBUG ( 30): *** *** *** *** *** *** *** *** *** *** *** *** ***
*** *** ***
I/DEBUG ( 30): Build fingerprint: 'generic/sdk/generic:2.3.1/
GSI11/93351:eng/test-keys'
I/DEBUG ( 30): pid: 299, tid: 299 >>> ./cast <<<
I/DEBUG ( 30): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault
addr 00000000
I/DEBUG ( 30): r0 000097b0 r1 00000000 r2 00000006 r3 000097b0
I/DEBUG ( 30): r4 00000000 r5 be8f0c84 r6 be8f0cb0 r7 000097b0
I/DEBUG ( 30): r8 00000000 r9 00000000 10 00000000 fp 00000000
I/DEBUG ( 30): ip 000098c8 sp be8f0c68 lr 80005ca7 pc
00000000 cpsr 00000010
I/DEBUG ( 30): #00 pc 00000000
I/DEBUG ( 30): #01 pc 00005ca4 /data/tests/libcast.so
I/DEBUG ( 30):
I/DEBUG ( 30): code around pc:
I/DEBUG ( 30):
I/DEBUG ( 30): code around lr:
I/DEBUG ( 30): 80005c84 60ab606b 930760eb 612b2310 91056803
I/DEBUG ( 30): 80005c94 91019200 95039602 69dc2206 1c3b9904
I/DEBUG ( 30): 80005ca4 9a0747a0 d02e2a00 200668eb 40011c19
I/DEBUG ( 30): 80005cb4 d0282906 686c68a9 4020400c d0222806
I/DEBUG ( 30): 80005cc4 40012005 d01d2904 d1142b00 2b009b04
I/DEBUG ( 30):
I/DEBUG ( 30): stack:
I/DEBUG ( 30): be8f0c28 afd42664 /system/lib/libc.so
I/DEBUG ( 30): be8f0c2c 0000a008 [heap]
I/DEBUG ( 30): be8f0c30 0000001c
I/DEBUG ( 30): be8f0c34 afd18407 /system/lib/libc.so
I/DEBUG ( 30): be8f0c38 afd42664 /system/lib/libc.so
I/DEBUG ( 30): be8f0c3c 00000001
I/DEBUG ( 30): be8f0c40 be8f0c94
I/DEBUG ( 30): be8f0c44 afd18453 /system/lib/libc.so
I/DEBUG ( 30): be8f0c48 afd42664 /system/lib/libc.so
I/DEBUG ( 30): be8f0c4c afd19321 /system/lib/libc.so
I/DEBUG ( 30): be8f0c50 00000001
I/DEBUG ( 30): be8f0c54 00000000
I/DEBUG ( 30): be8f0c58 be8f0c94
I/DEBUG ( 30): be8f0c5c 00000001
I/DEBUG ( 30): be8f0c60 df002777
I/DEBUG ( 30): be8f0c64 e3a070ad
I/DEBUG ( 30): #01 be8f0c68 be8f0cb0
I/DEBUG ( 30): be8f0c6c 000097a8 /data/tests/cast
I/DEBUG ( 30): be8f0c70 be8f0cb0
I/DEBUG ( 30): be8f0c74 be8f0c84
I/DEBUG ( 30): be8f0c78 00000000
I/DEBUG ( 30): be8f0c7c 000097a8 /data/tests/cast
I/DEBUG ( 30): be8f0c80 00000001
I/DEBUG ( 30): be8f0c84 00000000
I/DEBUG ( 30): be8f0c88 00000000
I/DEBUG ( 30): be8f0c8c 00000000
I/DEBUG ( 30): be8f0c90 00000000
I/DEBUG ( 30): be8f0c94 00000010
I/DEBUG ( 30): be8f0c98 00000002
I/DEBUG ( 30): be8f0c9c 00000000
I/DEBUG ( 30): be8f0ca0 00000001
I/DEBUG ( 30): be8f0ca4 afd41504 /system/lib/libc.so
I/DEBUG ( 30): be8f0ca8 be8f0cec
I/DEBUG ( 30): be8f0cac 00008637 /data/tests/cast
I/BootReceiver( 59): Copying /data/tombstones/tombstone_01 to
DropBox (SYSTEM_TOMBSTONE)

[xxxx@fc14androidr9 plain_c]$ arm-linux-androideabi-addr2line -e ./
libcast.so 00005ca4
/tmp/ndk/src/build/../gcc/gcc-4.4.3/libstdc++-v3/libsupc++/dyncast.cc:
47

alan

unread,
Mar 24, 2011, 1:28:44 PM3/24/11
to andro...@googlegroups.com, Marcel Smit
i think you need to link against gnu_stl to enable rtti

mcorino

unread,
Mar 24, 2011, 6:25:47 PM3/24/11
to android-ndk
Yes, the static gnu_stl library.
Which is exactly what is done here.

mcorino

unread,
Mar 25, 2011, 6:55:41 AM3/25/11
to android-ndk
I think I have found a way to circumvent this BAD support of RTTI in
libsup++.
By changing the single build step for the 'cast' executable to 2
separate steps; first compiling to 'cast.o' and next linking to 'cast'
I was able to force the link order to have the linker consider the
libsup++ library before the cast_lib.so.
In that case the dynamic_cast<> code in the main executable is linked
to the code in libsup++ (like the code in cast_lib is as well) before
the linker encounters the exported symbols from cast_lib.

The test now runs with crashing.

Still this sucks big time. For porting any serious C++ framework using
RTTI you will have to statically link the libsup++ code into EVERY
shared library and executable.

Does anyone know (Davide Turner?) if there is any plan to improve on
this poor support of RTTI?

Marcel Smit

unread,
Mar 29, 2011, 4:39:00 AM3/29/11
to android-ndk
Hi all,

Anyone else any ideas???

Thanks in advance!

Marcel.
Reply all
Reply to author
Forward
0 new messages