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 v4] 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                 | 12 ++++++++++++
 stdio-common/reg-printf.c |  7 ++++---
 stdio-common/reg-type.c   |  7 ++++---
 stdio-common/vfprintf.c   |  7 +++++++
 4 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 171e05e..bc2436c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2013-03-01  Peng Haitao  <penght@cn.fujitsu.com>
 
+	[BZ #14267]
+	* stdio-common/reg-printf.c: __libc_lock_define_initialized changed to
+	__libc_rwlock_define_initialized.
+	Parameter 'lock' changed to global lock 'lock_fun_type'.
+	* stdio-common/reg-type.c: __libc_lock_define_initialized changed to
+	__libc_rwlock_define.
+	Parameter 'lock' changed to global lock 'lock_fun_type'.
+	* stdio-common/vfprintf.c (vfprintf): Lock around use of
+	__printf_function_table and __printf_va_arg_table.
+
+2013-03-01  Peng Haitao  <penght@cn.fujitsu.com>
+
 	[BZ #14333]
 	* stdlib/cxa_atexit.c: Do not include bits/libc-lock.h.
 	(__libc_lock_define_initialized): Parameter 'lock' changed to global
diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c
index ff68b94..3964723 100644
--- a/stdio-common/reg-printf.c
+++ b/stdio-common/reg-printf.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
+   Copyright 2013 FUJITSU LIMITED
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -28,7 +29,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 +51,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 +71,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 402ec06..cd12932 100644
--- a/stdio-common/reg-type.c
+++ b/stdio-common/reg-type.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 2009-2013 Free Software Foundation, Inc.
+   Copyright 2013 FUJITSU LIMITED
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -25,7 +26,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 +36,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 +55,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 89126d2..77da72a 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
+   Copyright 2013 FUJITSU LIMITED
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -215,6 +216,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
@@ -1306,6 +1308,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);
@@ -2034,6 +2038,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.8.1.2


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