cppunit: gcc 4.2 vs 4.6 and libreoffice too

Andriy Gapon avg at FreeBSD.org
Wed Jul 25 14:31:30 UTC 2012

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 '^\*'

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
    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

More information about the freebsd-office mailing list