Date: Wed, 25 Jul 2012 17:31:27 +0300 From: Andriy Gapon <avg@FreeBSD.org> To: Yi-Jheng Lin <yzlin@FreeBSD.org>, office@FreeBSD.org, Jung-uk Kim <jkim@FreeBSD.org> Subject: cppunit: gcc 4.2 vs 4.6 and libreoffice too Message-ID: <5010033F.3060907@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
There is a well known problem of not being able to build the libreoffice port with GCC 4.6 if the cppunit port is built with GCC 4.2. The problem is manifested as a crash during cppunit-based tests. E.g. for me it happened here: - start unit test #1 on library ../../unxfbsd.pro/lib/libqa_sal_types.so ... ../../unxfbsd.pro/bin/cppunittester ../../unxfbsd.pro/lib/libqa_sal_types.so Let's try to unravel this issue step by step. The crash happens because of std::logic_error exception with what being "basic_string::_S_construct NULL". This exception happens when an std::string is constructed from a NULL C-string. According to a backtrace that I obtained the exception is triggered in src/cppunit/TypeInfoHelper.cpp, TypeInfoHelper::getClassName() method: c_name = abi::__cxa_demangle( info.name(), 0, 0, &status ); std::string name( c_name ); Unfortunately the cppunit code doesn't verify neither status produced by abi::__cxa_demangle nor its return value. In general std::type_info::name() is not supposed to a return a name that abi::__cxa_demangle would not understand. But shit happens and diagnostic information never hurts. Then I established that depending on a compiler used to compile cppunit std::type_info::name() returns either "*N12_GLOBAL__N_14TestE" for gcc 4.2 or "N12_GLOBAL__N_14TestE" for 4.6 (without the leading asterisk) in the test where the crash happens. The mangled name with the leading asterisk is not valid according to C++ ABI, but it is produced by GCC 4.6: $ strings -a -n9 unxfbsd.pro/lib/libqa_sal_types.so | fgrep TestE | grep '^\*' *N12_GLOBAL__N_14TestE *N7CppUnit16TestSuiteFactoryIN12_GLOBAL__N_14TestEEE *N7CppUnit25ConcretTestFixtureFactoryIN12_GLOBAL__N_14TestEEE *N7CppUnit23TestSuiteBuilderContextIN12_GLOBAL__N_14TestEEE *N7CppUnit10TestCallerIN12_GLOBAL__N_14TestEEE It seems that GCC 4.6 uses that leading asterisk for some internal purposed and it is supposed to be hidden/ignored. Unfortunately, it seems that std::type_info::name() is an inline method and thus it can not be really used for guarantee ABI compatibility across GCC versions. To show what I mean here is how std::type_info::name() is implemented in our base gcc (see /usr/include/c++/4.2/typeinfo): const char* name() const { return __name; } Now the same from GCC 4.6 (/usr/local/lib/gcc46/include/c++/typeinfo in my environment): const char* name() const { return __name[0] == '*' ? __name + 1 : __name; } So, as we can see, the later GCC knows about the asterisk and hides it from callers. GCC 4.2 doesn't know about it and so it returns __name as is. Due to inlining the code compiled by GCC 4.2 may incorrectly return typeinfo::name for code compiled with GCC 4.6. This is what happens in libreoffice case and is the root cause of the problem. I suggest the following patch to cppunit to work around this problem: --- src/cppunit/TypeInfoHelper.cpp.orig 2012-07-25 16:51:42.684996802 +0300 +++ src/cppunit/TypeInfoHelper.cpp 2012-07-25 16:59:06.149667846 +0300 @@ -21,7 +22,10 @@ TypeInfoHelper::getClassName( const std: int status = 0; char* c_name = 0; - c_name = abi::__cxa_demangle( info.name(), 0, 0, &status ); + const char* m_name = info.name(); + if (m_name[0] == '*') // inlined std::type_info::name() of older GXX + m_name++; + c_name = abi::__cxa_demangle( m_name, 0, 0, &status ); std::string name( c_name ); free( c_name ); Basically the added code does the same thing as GCC 4.6 std::type_info::name(). I've verified that I can build and use libreoffice with GCC 4.6 while cppunit is built with the base GCC and the above patch. -- Andriy Gapon
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5010033F.3060907>