This is the mail archive of the libc-alpha@sourceware.org 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]

[PATCH v2] Make fprintf() function to multithread-safe


fprintf() uses static variables __printf_function_table and
__printf_va_arg_table indirectly, which are not protected. It is
not safe in multithread circumstance.

When call fprintf() and register_printf_specifier() simultaneously
in multithread circumstance, the following case will cause unsafe.
The case has two threads: A and B.

a. thread B call register_printf_specifier('W', print_widget, print_widget_arginfo)
b. thread A call fprintf (stdout, "|%W|\n", &mywidget), when judge
   __printf_function_table is not NULL, but not output &mywidget
c. thread B call register_printf_specifier('W', NULL, NULL)
d. thread A output &mywidget when __printf_function_table is NULL
e. programme will Segmentation fault

Signed-off-by: Peng Haitao <penght@cn.fujitsu.com>
---
 ChangeLog                 |    5 +++++
 stdio-common/reg-printf.c |    6 +++---
 stdio-common/reg-type.c   |    6 +++---
 stdio-common/vfprintf.c   |    6 ++++++
 4 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 102ccba..429c632 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2012-06-21  Peng Haitao  <penght@cn.fujitsu.com>
+
+	* stdio-common/vfprintf.c (vfprintf): Lock around use of
+	__printf_function_table and __printf_va_arg_table.
+
 2012-06-18  H.J. Lu  <hongjiu.lu@intel.com>
 
 	[BZ #14117]
diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c
index 30bf7da..56e2b37 100644
--- a/stdio-common/reg-printf.c
+++ b/stdio-common/reg-printf.c
@@ -28,7 +28,7 @@ libc_freeres_ptr (printf_arginfo_size_function **__printf_arginfo_table)
   attribute_hidden;
 printf_function **__printf_function_table attribute_hidden;
 
-__libc_lock_define_initialized (static, lock)
+__libc_rwlock_define_initialized (, lock_fun_type);
 
 int __register_printf_specifier (int, printf_function,
 				 printf_arginfo_size_function);
@@ -50,7 +50,7 @@ __register_printf_specifier (spec, converter, arginfo)
     }
 
   int result = 0;
-  __libc_lock_lock (lock);
+  __libc_rwlock_wrlock (lock_fun_type);
 
   if (__printf_function_table == NULL)
     {
@@ -70,7 +70,7 @@ __register_printf_specifier (spec, converter, arginfo)
   __printf_arginfo_table[spec] = arginfo;
 
  out:
-  __libc_lock_unlock (lock);
+  __libc_rwlock_unlock (lock_fun_type);
 
   return result;
 }
diff --git a/stdio-common/reg-type.c b/stdio-common/reg-type.c
index 31c7472..bd55e9c 100644
--- a/stdio-common/reg-type.c
+++ b/stdio-common/reg-type.c
@@ -25,7 +25,7 @@
 libc_freeres_ptr (printf_va_arg_function **__printf_va_arg_table)
   attribute_hidden;
 
-__libc_lock_define_initialized (static, lock);
+__libc_rwlock_define (extern, lock_fun_type);
 
 /* Last type allocated.  */
 static int pa_next_type = PA_LAST;
@@ -35,7 +35,7 @@ int
 __register_printf_type (printf_va_arg_function fct)
 {
   int result = -1;
-  __libc_lock_lock (lock);
+  __libc_rwlock_wrlock (lock_fun_type);
 
   if (__printf_va_arg_table == NULL)
     {
@@ -54,7 +54,7 @@ __register_printf_type (printf_va_arg_function fct)
     }
 
  out:
-  __libc_lock_unlock (lock);
+  __libc_rwlock_unlock (lock_fun_type);
 
   return result;
 }
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index d569034..5d082cf 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -195,6 +195,7 @@ static CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, const char *)
      __THROW internal_function;
 #endif
 
+__libc_rwlock_define (extern, lock_fun_type);
 
 /* The function itself.  */
 int
@@ -1319,6 +1320,8 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
   _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
   _IO_flockfile (s);
 
+  __libc_rwlock_rdlock (lock_fun_type);
+
   /* Write the literal text before the first format.  */
   outstring ((const UCHAR_T *) format,
 	     lead_str_end - (const UCHAR_T *) format);
@@ -2047,6 +2050,9 @@ do_positional:
 all_done:
   free (args_malloced);
   free (workstart);
+
+  __libc_rwlock_unlock (lock_fun_type);
+
   /* Unlock the stream.  */
   _IO_funlockfile (s);
   _IO_cleanup_region_end (0);
-- 
1.7.10.2


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