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]

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


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