Patchwork Always do locking when accessing streams (bug 15142, bug 14697)

login
register
mail settings
Submitter Andreas Schwab
Date Feb. 13, 2020, 2 p.m.
Message ID <mvmy2t6a8ok.fsf@suse.de>
Download mbox | patch
Permalink /patch/38028/
State New
Headers show

Comments

Andreas Schwab - Feb. 13, 2020, 2 p.m.
Now that abort no longer calls fflush there is no reason to avoid locking
the stdio streams anywhere.  This fixes a conformance issue and potential
heap corruption during exit.  The test nptl/tst-stdio1 is removed as that
was expecting the problematic behaviour.
---
 libio/genops.c    | 43 +++++++++---------------------------
 libio/libioP.h    |  1 -
 nptl/Makefile     |  2 +-
 nptl/tst-stdio1.c | 56 -----------------------------------------------
 4 files changed, 11 insertions(+), 91 deletions(-)
 delete mode 100644 nptl/tst-stdio1.c
Florian Weimer - Feb. 16, 2020, 1:38 p.m.
* Andreas Schwab:

> Now that abort no longer calls fflush there is no reason to avoid locking
> the stdio streams anywhere.  This fixes a conformance issue and potential
> heap corruption during exit.  The test nptl/tst-stdio1 is removed as that
> was expecting the problematic behaviour.

I'm not sure if the justification is correct.  We don't know if there
are programs which call flockfile on some file and expect exit to
still work (and terminate the program), which is part of what
nptl/tst-stdio1 tests.

If there are such programs, we may need to make the new behavior
conditional on a new symbol version for exit.  But I guess we can put
in your patch now and see if testing shows any problems.

Patch

diff --git a/libio/genops.c b/libio/genops.c
index 28419cc963..0fbdbeca7c 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -682,7 +682,7 @@  _IO_adjust_column (unsigned start, const char *line, int count)
 libc_hidden_def (_IO_adjust_column)
 
 int
-_IO_flush_all_lockp (int do_lock)
+_IO_flush_all (void)
 {
   int result = 0;
   FILE *fp;
@@ -695,8 +695,7 @@  _IO_flush_all_lockp (int do_lock)
   for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
     {
       run_fp = fp;
-      if (do_lock)
-	_IO_flockfile (fp);
+      _IO_flockfile (fp);
 
       if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
 	   || (_IO_vtable_offset (fp) == 0
@@ -706,8 +705,7 @@  _IO_flush_all_lockp (int do_lock)
 	  && _IO_OVERFLOW (fp, EOF) == EOF)
 	result = EOF;
 
-      if (do_lock)
-	_IO_funlockfile (fp);
+      _IO_funlockfile (fp);
       run_fp = NULL;
     }
 
@@ -718,14 +716,6 @@  _IO_flush_all_lockp (int do_lock)
 
   return result;
 }
-
-
-int
-_IO_flush_all (void)
-{
-  /* We want locking.  */
-  return _IO_flush_all_lockp (1);
-}
 libc_hidden_def (_IO_flush_all)
 
 void
@@ -791,6 +781,9 @@  _IO_unbuffer_all (void)
     {
       int legacy = 0;
 
+      run_fp = fp;
+      _IO_flockfile (fp);
+
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
       if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
 	legacy = 1;
@@ -800,18 +793,6 @@  _IO_unbuffer_all (void)
 	  /* Iff stream is un-orientated, it wasn't used. */
 	  && (legacy || fp->_mode != 0))
 	{
-#ifdef _IO_MTSAFE_IO
-	  int cnt;
-#define MAXTRIES 2
-	  for (cnt = 0; cnt < MAXTRIES; ++cnt)
-	    if (fp->_lock == NULL || _IO_lock_trylock (*fp->_lock) == 0)
-	      break;
-	    else
-	      /* Give the other thread time to finish up its use of the
-		 stream.  */
-	      __sched_yield ();
-#endif
-
 	  if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
 	    {
 	      fp->_flags |= _IO_USER_BUF;
@@ -825,17 +806,15 @@  _IO_unbuffer_all (void)
 
 	  if (! legacy && fp->_mode > 0)
 	    _IO_wsetb (fp, NULL, NULL, 0);
-
-#ifdef _IO_MTSAFE_IO
-	  if (cnt < MAXTRIES && fp->_lock != NULL)
-	    _IO_lock_unlock (*fp->_lock);
-#endif
 	}
 
       /* Make sure that never again the wide char functions can be
 	 used.  */
       if (! legacy)
 	fp->_mode = -1;
+
+      _IO_funlockfile (fp);
+      run_fp = NULL;
     }
 
 #ifdef _IO_MTSAFE_IO
@@ -861,9 +840,7 @@  libc_freeres_fn (buffer_free)
 int
 _IO_cleanup (void)
 {
-  /* We do *not* want locking.  Some threads might use streams but
-     that is their problem, we flush them underneath them.  */
-  int result = _IO_flush_all_lockp (0);
+  int result = _IO_flush_all ();
 
   /* We currently don't have a reliable mechanism for making sure that
      C++ static destructors are executed in the correct order.
diff --git a/libio/libioP.h b/libio/libioP.h
index 7e446e3030..55697b27cb 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -487,7 +487,6 @@  extern int _IO_new_do_write (FILE *, const char *, size_t);
 extern int _IO_old_do_write (FILE *, const char *, size_t);
 extern int _IO_wdo_write (FILE *, const wchar_t *, size_t);
 libc_hidden_proto (_IO_wdo_write)
-extern int _IO_flush_all_lockp (int);
 extern int _IO_flush_all (void);
 libc_hidden_proto (_IO_flush_all)
 extern int _IO_cleanup (void);
diff --git a/nptl/Makefile b/nptl/Makefile
index 6f210d60e3..d248f1ddb6 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -277,7 +277,7 @@  tests = tst-attr2 tst-attr3 tst-default-attr \
 	tst-signal6 \
 	tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \
 	tst-exit1 tst-exit2 tst-exit3 \
-	tst-stdio1 tst-stdio2 \
+	tst-stdio2 \
 	tst-stack1 tst-stack2 tst-stack3 tst-stack4 \
 	tst-pthread-attr-affinity tst-pthread-mutexattr \
 	tst-unload \
diff --git a/nptl/tst-stdio1.c b/nptl/tst-stdio1.c
deleted file mode 100644
index 66696a92ee..0000000000
--- a/nptl/tst-stdio1.c
+++ /dev/null
@@ -1,56 +0,0 @@ 
-/* Copyright (C) 2002-2020 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <unistd.h>
-
-static int do_test (void);
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
-
-static void *tf (void *a)
-{
-  flockfile (stdout);
-  /* This call should never return.  */
-  return a;
-}
-
-
-int
-do_test (void)
-{
-  pthread_t th;
-
-  flockfile (stdout);
-
-  if (pthread_create (&th, NULL, tf, NULL) != 0)
-    {
-      write_message ("create failed\n");
-      _exit (1);
-    }
-
-  delayed_exit (1);
-  xpthread_join (th);
-
-  puts ("join returned");
-
-  return 1;
-}