This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
Problem of l64a(3) on multithread application
- From: Shunichi Sagawa <s-sagawa at jp dot fujitsu dot com>
- To: libc-alpha <libc-alpha at sources dot redhat dot com>
- Date: Tue, 22 Feb 2005 18:34:59 +0900
- Subject: Problem of l64a(3) on multithread application
Hello,
In multithreaded application, the result of this function is likely
to be overwritten with the result of another thread.
l64a() returns the result with the pointer to a static buffer and
the static buffer is not protected for the multithreaded access.
I think that the static buffer should be protected.
<test program start>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define MAX 10000
unsigned long int number_one = 1000000000;
unsigned long int number_two = 2000000000;
//the result of l64a(number_one) should be string_one
char *string_one = ".cgav";
//the result of l64a(number_two) should be string_two
char *string_two = ".ENBr/";
int find_error = 0;
void *thread_l64a()
{
char *str_one;
char *str_two;
while (!find_error) {
str_one = l64a(number_one);
if(strcmp(string_one, str_one)) {
find_error = 1;
}
str_two = l64a(number_two);
if(strcmp(string_two, str_two)) {
find_error = 1;
}
}
}
int main()
{
int thread_create_ret;
pthread_t l64a_one_id, l64a_two_id;
thread_create_ret =
pthread_create(&l64a_one_id, NULL, (void *)thread_l64a, NULL);
if(thread_create_ret != 0) {
printf("thread create error\n");
exit(1);
}
thread_create_ret =
pthread_create(&l64a_two_id, NULL, (void *)thread_l64a, NULL);
if(thread_create_ret != 0) {
printf("thread create error\n");
exit(1);
}
pthread_join(l64a_one_id, NULL);
pthread_join(l64a_two_id, NULL);
if(find_error)
printf("The return value of function l64a() is error!\n");
return 0;
}
<test program end>
# ./tst-l64a
The return value of function l64a() is error!
#
<patch start>
diff -Nur glibc-2.3.4/stdlib/l64a.c glibc-2.3.4.new/stdlib/l64a.c
--- glibc-2.3.4/stdlib/l64a.c 2005-02-22 09:57:00.000000000 +0900
+++ glibc-2.3.4.new/stdlib/l64a.c 2005-02-22 09:57:49.000000000 +0900
@@ -18,6 +18,21 @@
02111-1307 USA. */
#include <stdlib.h>
+#include <bits/libc-lock.h>
+
+/* This is the key for the thread specific memory. */
+static __libc_key_t key;
+__libc_once_define (static, once);
+
+/* If nonzero the key allocation failed and we should better use a
+ static buffer than fail. */
+static char local_buf[7];
+static char *static_buf;
+
+/* Destructor for the thread-specific data. */
+static void init (void);
+static void free_key_mem (void *mem);
+static char *getbuffer (void);
/* Conversion table. */
static const char conv_table[64] =
@@ -37,8 +52,11 @@
long int n;
{
unsigned long int m = (unsigned long int) n;
- static char result[7];
+ char *buffer;
int cnt;
+ __libc_once (once, init);
+
+ buffer = getbuffer ();
/* The standard says that only 32 bits are used. */
m &= 0xffffffff;
@@ -49,10 +67,61 @@
for (cnt = 0; m > 0ul; ++cnt)
{
- result[cnt] = conv_table[m & 0x3f];
+ buffer[cnt] = conv_table[m & 0x3f];
m >>= 6;
}
- result[cnt] = '\0';
+ buffer[cnt] = '\0';
+
+ return buffer;
+}
+
+
+/* Initialize buffer. */
+static void
+init (void)
+{
+ if (__libc_key_create (&key, free_key_mem))
+ /* Creating the key failed. This means something really went
+ wrong. In any case use a static buffer which is better than
+ nothing. */
+ static_buf = local_buf;
+}
+
+
+/* Free the thread specific data, this is done if a thread terminates. */
+static void
+free_key_mem (void *mem)
+{
+ free (mem);
+ __libc_setspecific (key, NULL);
+}
+
+
+/* Return the buffer to be used. */
+static char *
+getbuffer (void)
+{
+ char *result;
+
+ if (static_buf != NULL)
+ result = static_buf;
+ else
+ {
+ /* We don't use the static buffer and so we have a key. Use it
+ to get the thread-specific buffer. */
+ result = __libc_getspecific (key);
+ if (result == NULL)
+ {
+ /* No buffer allocated so far. */
+ result = malloc (7);
+ if (result == NULL)
+ /* No more memory available. We use the static buffer. */
+ result = local_buf;
+ else
+ /* Set the tsd. */
+ __libc_setspecific (key, result);
+ }
+ }
return result;
}
<patch end>
Best Regards,
Shunichi Sagawa