Hi community!
I believe I have discovered that uClibc++ incorrectly implements C++ exception ABI, allocating not enough memory in the "__cxxabiv1::__cxa_allocate_exception": /// code begin /// retval = malloc (thrown_size + sizeof(__cxa_exception)); /// code end /// uClibc++ allocates "thrown_size + sizeof(__cxa_exception)" while stdlibc++ allocates "thrown_size += sizeof (__cxa_refcounted_exception);" since 2009-01-07 (https://gcc.gnu.org/bugzilla/attachment.cgi?id=17047) . The "__cxa_refcounted_exception" is wrapper around "__cxa_exception" and thus bigger than "__cxa_exception" alone. That causes memory corruption (buffer overflow) inside "__cxxabiv1::__cxa_throw" which is implemented by GCC's libsupc++: /// code begin (gcc-5.2.0/libstdc++-v3/libsupc++/eh_throw.cc:69) /// __cxa_refcounted_exception *header = __get_refcounted_exception_header_from_obj (obj); header->referenceCount = 1; /// code end /// In the code above, the "header->referenceCount = 1" writes in memory preceding region allocated for both thrown exception object and exception structure. The "obj" is pointer to memory allocated by "__cxxabiv1::__cxa_allocate_exception", the "__get_refcounted_exception_header_from_obj (obj)" is defined as: /// code begin /// static inline __cxa_refcounted_exception * __get_refcounted_exception_header_from_obj (void *ptr) { return reinterpret_cast<__cxa_refcounted_exception *>(ptr) - 1; } /// code end /// Thus GCC's libsupc++ expects enough memory allocated preceding exception object to keep structure "__cxa_refcounted_exception", but uClibc++ allocates only "sizeof(__cxa_exception)" bytes before exception object. When binary is compiled for OpenWRT's musl libc standard library, the program crashes with SIGSEGV in the "free" call from "__cxxabiv1::__cxa_free_exception" because musl is very sensitive for memory corruption (musl's malloc stores meta-information about memory region in 8 bytes right before memory chunk itself). When compiled against glibc, the segmentation fault does not happen immediately in the "__cxxabiv1::__cxa_free_exception", but memory corruptions still should take place, yielding undefined behavior. I would like someone experienced with OpenWRT, musl and uClibc++ to review and verify my discoveries, because there is chance that I miss some magic compile flag that makes OpenWRT to build binaries with other implementation of "__cxxabiv1::__cxa_throw" or I miss something else. This bug seems to exist for many years (since 2009), so I wonder why no one noticed that try-catch corrupts memory and it completely does not work for musl-based builds. My quick research shown that most of the OpenWRT packages do not use C++ exceptions at all, that is probably why. Also musl libc which makes this issue very visible, was adopted just recently, so perhaps not much time passed yet. For your convenience, I have created OpenWRT package and feed for this test case: package: https://github.com/CoolSpot/openwrt-test/throw-catch-sigsegv feed: https://github.com/CoolSpot/openwrt-test-packages ### Installing the feed cd ~/Documents/openwrt echo "src-git openwrttest https://github.com/coolspot/openwrt-test-packages.git" >> ./feeds.conf ./scripts/feeds update openwrttest ./scripts/feeds install -a -p openwrttest ### Building the package make menuconfig # In the menuconfig select the package Test/sub-test/throw-catch-sigsegv to be built make package/throw-catch-sigsegv/install # Copy the package on the device (or VM) scp ./bin/malta/packages/openwrttest/throw-catch-sigsegv_2016-02-25_malta_mips.ipk qemu:/tmp/ # on the device (or VM) root@OpenWrt:~# opkg install /tmp/throw-catch-sigsegv_2016-02-25_malta_mips.ipk I am using following setup for reproducing: OpenWRT commit 4885087731e4ee9ac9823bd5cf3e777eecfd33d9 (Tue Feb 23 14:40:40 2016 +0000) uClibc++ compiled with DODEBUG="y" (CONFIG_DEBUG does not affect uClibc++). qemu-mips version 2.3.0 (Debian 1:2.3+dfsg-5ubuntu9.1) OpenWRT diffconfig: CONFIG_TARGET_malta=y CONFIG_TARGET_malta_be=y CONFIG_TARGET_malta_be_Default=y CONFIG_DEBUG=y CONFIG_KERNEL_PERF_EVENTS=y CONFIG_KERNEL_PROC_PAGE_MONITOR=y CONFIG_KERNEL_PROFILING=y CONFIG_KERNEL_SLABINFO=y CONFIG_KERNEL_SLUB_DEBUG=y CONFIG_KERNEL_SLUB_DEBUG_ON=y CONFIG_NO_STRIP=y CONFIG_OPENSSL_WITH_EC=y CONFIG_PACKAGE_ar=y CONFIG_PACKAGE_binutils=y CONFIG_PACKAGE_block-mount=y CONFIG_PACKAGE_ethtool=y CONFIG_PACKAGE_gdbserver=y CONFIG_PACKAGE_kmod-crypto-hash=y CONFIG_PACKAGE_kmod-fs-ext4=y CONFIG_PACKAGE_kmod-lib-crc16=y CONFIG_PACKAGE_libbfd=y CONFIG_PACKAGE_libcap=y CONFIG_PACKAGE_libncurses=y CONFIG_PACKAGE_libnl=y CONFIG_PACKAGE_libnl-core=y CONFIG_PACKAGE_libnl-genl=y CONFIG_PACKAGE_libnl-nf=y CONFIG_PACKAGE_libnl-route=y CONFIG_PACKAGE_libopcodes=y CONFIG_PACKAGE_libopenssl=y CONFIG_PACKAGE_libpcap=y CONFIG_PACKAGE_libpcre=y CONFIG_PACKAGE_libpthread=y CONFIG_PACKAGE_librt=y CONFIG_PACKAGE_objdump=y CONFIG_PACKAGE_screen=y CONFIG_PACKAGE_strace=y CONFIG_PACKAGE_throw-catch-sigsegv=y CONFIG_PACKAGE_uclibcxx=y CONFIG_TARGET_EXT4_BLOCKSIZE=4096 CONFIG_TARGET_EXT4_BLOCKSIZE_4K=y CONFIG_TARGET_EXT4_MAXINODE=6000 CONFIG_TARGET_EXT4_RESERVED_PCT=0 CONFIG_TARGET_ROOTFS_EXT4FS=y CONFIG_TARGET_ROOTFS_PARTSIZE=256 -- Best regards, Ivan Koldaev.
_______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel