Problem of l64a(3) on multithread application
Shunichi Sagawa
s-sagawa@jp.fujitsu.com
Tue Feb 22 09:51:00 GMT 2005
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
More information about the Libc-alpha
mailing list