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