This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Re: Potential locking issue in newlocale
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Paolo Carlini <pcarlini at suse dot de>
- Cc: libc-alpha at sources dot redhat dot com, Ulrich dot Weigand at de dot ibm dot com, libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Fri, 16 Jul 2004 11:22:07 +0200
- Subject: Re: Potential locking issue in newlocale
- References: <40F79EAB.1060107@suse.de>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
On Fri, Jul 16, 2004 at 11:23:55AM +0200, Paolo Carlini wrote:
> > And in fact, in one crash I have analysed, it looks as if glibc-internal
> > data structures are corrupted.
>
> As a very empirical data point, supporting your conjecture, a few days ago
> I tried wrapping in a mutex the call of
> locale::facet::_S_create_c_locale(__cloc, __s)
> present in locale::_Impl::_Impl(const char*, size_t).
> The former, I recall, is just:
>
> void
> locale::facet::_S_create_c_locale(__c_locale& __cloc, const char* __s,
> __c_locale __old)
> {
> __cloc = __newlocale(1 << LC_ALL, __s, __old);
> if (!__cloc)
> {
> // This named locale is not supported by the underlying OS.
> __throw_runtime_error(__N("locale::facet::_S_create_c_locale "
> "name not valid"));
> }
> }
>
> and, to my *very* big surprise, the testcase did *not* fail anymore on 4-way
> x86_64...
Are you sure the libstdc++ side is ok?
I run ltrace on the program and rewrote it in C and certainly can't get this
to fail on 4 way x86_64 (while the 12658_thread-1.cc testcase segfaults
quite often, but not always).
My biggest surprise is the
const int max_locales = 10;
...
for (int i = 0; i < max_loop_count; ++i)
{
int k = i % max_locales;
loc[k] = std::locale::global(loc[k]);
if (i % 37 == 0)
loc[k] = loc[k].combine<std::ctype<char> >(loc_c);
}
loop is not actually modulo 10, but modulo 11 in the C library calls,
as can be proven by inserting e.g.
printf ("%d %d %s\n", i, k, ::setlocale (LC_ALL, NULL));
before the if (i % 37 == 0) line.
It will print (if I call thread_main from main and don't create any
threads):
0 0 fr_FR
1 1 en_US
...
9 9 en_US
10 0 C
11 1 fr_FR
12 2 en_US
...
19 9 fr_FR
20 0 en_US
21 1 C
22 2 fr_FR
23 3 en_US
...
That surely doesn't sound right to me (as well as that once loc[k]
is combined with LC_CTYPE "C", the setlocale calls don't take it
into account).
#include <locale.h>
#include <pthread.h>
void *
tf (void *arg)
{
int n;
locale_t C = newlocale (LC_ALL_MASK, "C", NULL);
locale_t old = uselocale (C);
uselocale (old);
uselocale (C);
uselocale (old);
int i, j;
struct { locale_t l; locale_t d[10]; } s[10];
for (i = 0; i < 10; ++i)
{
locale_t l = newlocale (LC_ALL_MASK, (i & 1) ? "en_US" : "de_DE",
NULL);
s[i].d[0] = duplocale (l);
s[i].d[1] = duplocale (l);
s[i].d[2] = duplocale (l);
s[i].d[3] = duplocale (l);
s[i].d[4] = duplocale (l);
s[i].d[5] = duplocale (l);
old = uselocale (s[i].d[5]);
uselocale (old);
s[i].d[6] = duplocale (l);
s[i].d[7] = duplocale (l);
old = uselocale (l);
uselocale (old);
uselocale (l);
uselocale (old);
s[i].d[8] = duplocale (l);
s[i].d[9] = duplocale (l);
freelocale (l);
}
for (n = 0; n < 100000; ++n)
{
i = n % 11;
setlocale (LC_ALL, i == 10 ? "C" : ((i & 1) ? "en_US" : "fr_FR"));
if ((n % 37) == 0 && n > 0 && n <= 370)
freelocale (s[i - 1].d[0]);
}
for (i = 0; i < 10; ++i)
for (j = 1; j < 10; ++j)
freelocale (s[i].d[j]);
freelocale (C);
return NULL;
}
int
main ()
{
pthread_t pth[20];
int i;
for (i = 0; i < 20; ++i)
pthread_create (&pth[i], NULL, tf, NULL);
for (i = 0; i < 20; i++)
pthread_join (pth[i], NULL);
return 0;
}
Jakub