C++ io, thread safety, and setlocale

John Ruttenberg rutt@chezrutt.com
Mon Apr 21 19:01:00 GMT 2003


Pehaps this is a FAQ, but I couldn't find anything.

I'm trying to port an application that uses C++ io and pthreads to AIX and am
having some problems.  I have tracked some of these down to a specific
interaction between C++ io and the ctype.h function isspace.  I finally got a
core dump that shows clearly something bad that is happening.  There is a
segfault in isspace (a libc.a function) in one thread and setlocale is on the
stack in a different thread.  With a little work, I figured out that gnu
libstdc++ calls setlocale in a thread unsafe way virutally all the time.

Here is a simple C++ program:

    #include <iostream>

    main()
    {
        std::cout << 77;
    }

Compile with g++ -pthread -g

Use gdb to set a break point at setlocale:

    gdb a.out
    b main
    (gdb) b main
    Breakpoint 1 at 0x100004cc: file hello.cxx, line 5.
    (gdb) r
    Starting program: /home/rutt/tmp/hello 
    [Switching to Thread 1]

    Breakpoint 1, main () at hello.cxx:5
    5	  std::cout << 12;
    (gdb) b setlocale
    Breakpoint 2 at 0xd01f2c94
    (gdb) c
    Continuing.

    Breakpoint 2, 0xd01f2c94 in setlocale () from /usr/lib/libc.a(shr.o)

    (gdb) where
    #0  0xd01f2c94 in setlocale () from /usr/lib/libc.a(shr.o)
    #1  0xd2b6aae4 in int std::__convert_from_v<long>(char*, int, char const*, long, int* const&, int)
        (__out=0x2ff22640 "", __size=0, __fmt=0x2ff22630 "%ld", __v=12, __prec=-1)
        at /home/rutt/gcc-3.2.2/build/powerpc-ibm-aix5.1.0.0/pthread/libstdc++-v3/include/powerpc-ibm-aix5.1.0.0/bits/c++locale.h:49
    #2  0xd2b62374 in std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_convert_int<long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, char, long) const (this=0xf0773e7c, __s=
          {<iterator<std::output_iterator_tag,void,void,void,void>> = {<No data fields>}, _M_sbuf = 0xf0773fd8, _M_failed = false}, __io=@0xf0774244, __fill=32 ' ', __mod=2 '\002', __modl=0 '\0', __v=12)
        at /home/rutt/gcc-3.2.2/build/powerpc-ibm-aix5.1.0.0/pthread/libstdc++-v3/include/bits/locale_facets.tcc:719
    #3  0xd2b61d98 in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, long) const (
        this=0x0, __s=
          {<iterator<std::output_iterator_tag,void,void,void,void>> = {<No data fields>}, _M_sbuf = 0x10000, _M_failed = false}, __io=@0xf076dba0, __fill=-1 ',b(B', __v=4098)
z        at /home/rutt/gcc-3.2.2/build/powerpc-ibm-aix5.1.0.0/pthread/libstdc++-v3/include/bits/locale_facets.tcc:893
    #4  0xd2b81778 in std::ostream::operator<<(long) (this=0xf077423c, __n=12)
        at /home/rutt/gcc-3.2.2/build/powerpc-ibm-aix5.1.0.0/pthread/libstdc++-v3/include/bits/locale_facets.h:740
    #5  0xd2b81d84 in std::ostream::operator<<(int) (this=0x1002, __n=0)
        at /home/rutt/gcc-3.2.2/build/powerpc-ibm-aix5.1.0.0/pthread/libstdc++-v3/include/ostream:7
    #6  0x100004d8 in main () at hello.cxx:5
    #7  0x100001dc in __start ()
    
And here is the code near c++locale.h:49 

  __convert_from_v(char* __out, const int __size, const char* __fmt,
                     _Tv __v, const __c_locale&, int __prec = -1)
    {
      char* __old = setlocale(LC_ALL, NULL);
      char* __sav = static_cast<char*>(malloc(strlen(__old) + 1));
      if (__sav)
        strcpy(__sav, __old);
      setlocale(LC_ALL, "C");

      int __ret;
#ifdef _GLIBCPP_USE_C99
      if (__prec >= 0)
        __ret = snprintf(__out, __size, __fmt, __prec, __v);
      else
        __ret = snprintf(__out, __size, __fmt, __v);
#else
      if (__prec >= 0)
        __ret = sprintf(__out, __fmt, __prec, __v);
      else
        __ret = sprintf(__out, __fmt, __v);
#endif
      setlocale(LC_ALL, __sav);
      free(__sav);
      return __ret;
    }

How can this be thread safe without some locking of some sort?



More information about the Libstdc++ mailing list