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