This is the mail archive of the
libc-help@sourceware.org
mailing list for the glibc project.
[RFC]setlocale() race condition
- From: Sharyathi Nagesh <sharyath at in dot ibm dot com>
- To: libc-help at sourceware dot org
- Cc: suzukikp at in dot ibm dot com, sripathi at in dot ibm dot com
- Date: Thu, 12 Jun 2008 09:15:06 +0530
- Subject: [RFC]setlocale() race condition
Hi
This problem was noticed with glibc shipped with distro, older version
of glibc 2.5-12, the problem is noticed after 8 hours of testing and
application crashed with SIGSEGV. My efforts to replicate the problem
with main line glibc was not successful, but I still feel the problem is
there even with main line glibc and wished to know your thoughts on this
issue
-----------------------------------------------------------------
Explanation:
This problem was noticed during PHP engine development, current
implementation calls setlocale() every time a page is requested. The
problem is noticed during stress test of this enging
setlocale() is being called on multiple threads. The exact api calls
are as follows
....
setlocale(LC_ALL,'C');
....
setlocale(LC_TYPE,'');
....
setlocale(LC_CTYPE,'C');
....
It was observed that after ~8 hours of testing, application crashed at
strcmp() call made from setlocale(), when I analyzed the dump it showed
that _nl_global_locale.__names[category] pointer was corrupted.
When I went through the code, I see a window of race condition where
one thread will call strcmp()(with in setlocale()) with current value of
_nl_global_locale.__names[category] passed as argument, while another
thread goes ahead and frees the string pointer pointed by
_nl_global_locale.__names[category].
Since the man page of setlocale() doesn't talk any thing about the call
`not being re-entrant` I assume setlocale() to be re-entrant
-----------------------------------------------------------------
Testing:
Didn't notice any regression with testing. Testing was done under
x86-64 box where the application was built as 32bit.
-----------------------------------------------------------------
Fix:
Similar fix, fixed the problem with distro glibc, where
__libc_lock_lock() is used instead of __libc_rwlock_rdlock()
Thanks
Yeehaw
Index: libc/locale/setlocale.c
===================================================================
--- libc.orig/locale/setlocale.c 2008-03-31 06:07:03.000000000 +0530
+++ libc/locale/setlocale.c 2008-06-12 08:59:45.000000000 +0530
@@ -234,10 +234,14 @@
if (locale == NULL)
return (char *) _nl_global_locale.__names[category];
+ __libc_rwlock_rdlock (__libc_setlocale_lock);
if (strcmp (locale, _nl_global_locale.__names[category]) == 0)
+ {
+ __libc_rwlock_unlock (__libc_setlocale_lock);
/* Changing to the same thing. */
return (char *) _nl_global_locale.__names[category];
-
+ }
+ __libc_rwlock_unlock (__libc_setlocale_lock);
/* We perhaps really have to load some data. So we determine the
path in which to look for the data now. The environment variable
`LOCPATH' must only be used when the binary has no SUID or SGID