[ANN] --enable-dbgutil: everyone gets a Debug STL!

Stephan Bergmann sbergman at redhat.com
Wed Apr 17 23:31:22 PDT 2013


On 04/17/2013 08:43 AM, Stephan Bergmann wrote:
> On 04/15/2013 03:34 PM, Michael Stahl wrote:
>> with commit f14f7a2e4568e3e85a0c8860beebd0376c5a8b51 MSVC builds will
>> link everything against the debug runtimes (MSVCRTD etc.), which enables
>> debug STL and other things.
> [...]
>> since we have this enabled on other GCC platforms for years i'm not much
>> concerned about breakage on MacOSX; it would be helpful though if
>> somebody could try what happens when you run the "subsequentcheck" tests
>> which apparently isn't possible over SSH.
>
> Another fallout is that, at least in
> my Mac OS X 10.7.5, Xcode 4.6.1, --enable-dbgutil --with-macosx-sdk=10.7
> master builds, writing numbers to std streams now suppresses all output
> to those streams, so that e.g., SAL_WARN("foo","bar") only writes
> "warn:foo:" to stderr (not even followed by a newline) and stops as soon
> as it would write the numeric pid.
>
> This is caused by basic_ostream::_M_insert
> (/usr/include/c++/4.2.1/bits/ostream.tcc) catching an exception from
> __check_facet(this->_M_num_put) and setting ios_base::badbit, which in
> turn results from this->_M_num_put unexpectedly being null.  Similar
> problems on (non-debug) Linux had been addressed with long ago with
> consistently exporting _ZGVNSt7num_put* and _ZNSt7num_put* symbols from
> all libraries.
>
> Why _GLIBCXX_DEBUG causes this problem on Mac OS X now, and how to solve
> it, is still unclear to me.

For the record, here is what happens:  At least on Mac OS X 10.7.5 with 
Xcode 4.6.2 (with Command Line Tools installed), building the C++ 
program test.cc

> #include <iostream>
> #include <sstream>
> int main() {
>   std::ostringstream s;
>   s << "a" << 1 << "b\n";
>   std::cout << s.str();
> }

with

> c++ -D_GLIBCXX_DEBUG test.cc

and running it (./a.out) prints only

> a

(not followed by a newline) to stdout, not

> a1b

(followed by a newline).

The reason is that in basic_ostream::_M_insert 
(/usr/include/c++/4.2.1/bits/ostream.tcc) the 
__check_facet(this->_M_num_put) call throws an exception, leading to 
this->_M_setstate(ios_base::badbit).

This is because _M_num_put is null, because in 
basic_ios::_M_cache_locale (/usr/include/c++/4.2.1/bits/basic_ios.tcc) 
the call to has_facet<__num_put_type>(__loc) returns false.

This is because in has_facet 
(/usr/include/c++/4.2.1/bits/locale_facets.tcc), the call to 
_Facet::id._M_id() (with _Facet being __num_put_type aka 
num_put<_CharT,ostreambuf_iterator<_CharT,_Traits>>, see 
/usr/include/c++/4.2.1/bits/basic_ios.h) returns a fresh __i >= 
__loc._M_impl->_M_facets_size.

This is because the static

> template <typename _CharT, typename _OutIter>
>   locale::id num_put<_CharT, _OutIter>::id;

(/usr/include/c++/4.2.1/bits/locale_facets.h) is emitted into test.s as

>   .section __DATA,__datacoal_nt,coalesced
>   .globl __ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE ## @_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE
>   .weak_definition __ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE
>   .align 3
> __ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE:
>   .space 8

so that a.out binds to this instance while libstdc++.6.dylib previously 
has used a binding to its own instance (in calls via 
std::ios_base::Init::Init -> ... -> 
std::has_facet<std::num_put<char,std::ostreambuf_iterator<char,std::char_traits<char>>>>, 
as can be observed in gdb).

Interestingly, while a.out contains its own weak definition of 
__ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE2idE, it 
has __ZNSt5ctypeIcE2idE -- i.e.,

> template<typename _CharT>
>   locale::id ctype<_CharT>::id;

(/usr/include/c++/4.2.1/bits/locale_facets.h) as an undefined reference 
(so binds to the definition in libstdc++.6.dylib).  Both are eventually 
needed from _M_cache_locale; the two mainly differ in the number of 
template parameters.

This all becomes irrelevant when compiling without -D_GLIBCXX_DEBUG, as 
then (/usr/include/c++/4.2.1/bits/c++config.h) 
_GLIBCXX_NAMESPACE_ASSOCIATION_DEBUG is 0 so that 
_GLIBCXX_EXTERN_TEMPLATE is 1, so that

> extern template class basic_ostringstream<char>;

(/usr/include/c++/4.2.1/bits/sstream.tcc) becomes visible and the call 
to 
std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>::basic_ostringstream(std::_Ios_Openmode) 
(aka 
__ZNSt19basic_ostringstreamIcSt11char_traitsIcESaIcEEC1ESt13_Ios_Openmode) 
in a.out calls directly into libstdc++.6.dylib, instead of carrying weak 
definitions of all the code involved above in a.out.

(It makes no difference whether to build with c++, clang++, or g++.  It 
also makes no difference whether to also specify 
-D_GLIBCXX_FULLY_DYNAMIC_STRING, which is known to be required in other 
circumstances like 
<http://lists.apple.com/archives/cocoa-dev/2009/Sep/msg01199.html> "Re: 
getline 'free' problem."  Also, results are the same at least with Xcode 
4.6.1 and Xcode 4.6.2.)

Stephan


More information about the LibreOffice mailing list