This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Potential locking issue in newlocale


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]