Fernando J. Pereda’s blag

May 25, 2010

iostreams are VERY thread-unsafe on Mac OS X

Filed under: blag — Tags: , , , — Fernando J. Pereda @ 8:19 am

This was both surprising and disgusting. Our in-house data acquisition software needs to convert lots of floats to ascii so that they can ve viewed in real time. This is very easy to do with a stringify-like function like the one found in paludis/paludis/util/stringify.hh.

stringify looks trivial, there’s no shared state nor there is any static data, so I thought that I could call stringify from several threads at the same time. I don’t think there’s any guarantee about thread safety of ostringstream’s operator<< but it looked like a safe assumption. Well, incorrect.

operator<< calls vsnprintf, which should be thread-safe by itself. However, OSX's vsnprintf ultimately calls localeconv_l, which is not thread-safe. And, you end up with something like this:

#0 0x96f734a9 in malloc_error_break ()
#1 0x96f6e497 in szone_error ()
#2 0x96e98503 in szone_free ()
#3 0x96e9836d in free ()
#4 0x96e97f24 in localeconv_l ()
#5 0x96e93335 in __vfprintf ()
#6 0x96ecb9b5 in vsnprintf ()
#7 0x0144615e in std::__convert_from_v ()
#8 0x01437d2a in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits > >::_M_insert_float ()
#9 0x0143803d in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits > >::do_put ()
#10 0x0144ab6a in std::ostream::_M_insert ()
#11 0x0000fb25 in std::basic_ostringstream<char, std::char_traits, std::allocator >::str () at sstream:217
...

Which means there’s no way of converting stuff to human readable in a thread-safe manner. I’m not sure whether I’m missing something or not… but this looks very fishy. I ended up adding a stupid big mutex around my stringify calls, but that looks more like a workaround that a final solution to the problem. Plus, this doesn’t protect ANY other uses of iostream’s operator<< such as loggers.

Ok… looks like that wasn’t a very accurate diagnostic. This is going to be more annoying than I thought.

— ferdy

April 27, 2009

Small C trivia

Filed under: blag — Tags: , , , — Fernando J. Pereda @ 8:50 am

This is somehow surprising the first time you see it and it is interesting to remind it to people from time to time. The question is easy, does this program always return 0? That is, are those summations the same?

If there’s a case when it doesn’t, provide a sample input and explain why it happens.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	float f[argc - 1];
	for (int i = 1; i < argc; i++)
		f[i - 1] = atof(argv[i]);
	float r1 = 0;
	for (int i = 0; i < argc - 1; i++)
		r1 += f[i];
	float r2 = 0;
	for (int i = argc - 2; i >= 0; i--)
		r2 += f[i];
	return r1 != r2;
}

As usual, I’ll post the solution in a couple of days or when someone gets it right (which is always the case :))

— fpereda

Update: correct typo spotted by Snaury.

Blog at WordPress.com.