This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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] Fix libstdc++/9523 (and more)


Hi,

This patch fixes libstdc++/9523 and a few other related problems in ios_base.

The standard streams (cin, cout, cerr, clog, wcin, wcout, wcerr, wclog) are
now only constructed once when the first object of type ios_base::Init is
constructed and are never destroyed, as required by 27.3 p2 and 27.4.2.1.6
p3.

ios_base::sync_with_stdio now destroys the stream buffers, creates new
buffers and installs them with rdbuf(), and does not otherwise modify
the state of the streams. This fixes 9523.

When the last ios_base::Init object is destroyed the standard output streams
(cout, cerr, clog, wcout, wcerr, wclog) are now flushed, as required by
27.4.2.1.6 p4. This in effect reverts the fix for libstdc++/5268, but it
appears that this is the required behavior and that the test case for 5268
has undefined behavior.

Regards,
Petur

2003-04-26  Petur Runolfsson  <peturr02 at ru dot is>

	PR libstdc++/9523
	* include/bits/ios_base.h (Init::_S_ios_create,
	Init::_S_ios_destroy):  Remove declarations.
	(Init::_S_ios_create_streams, Init::_S_ios_create_buffers,
	Init::_S_ios_flush, Init::_S_ios_destroy_buffers):  Declare
	* src/ios.cc (Init::_S_ios_create):  Remove
	(Init::_S_ios_create_streams):  Create streams with NULL buffers.
	(Init::_S_ios_create_buffers):  Create buffers and add to streams.
	(Init::_S_ios_flush):  Flush standard output streams.
	(Init::_S_ios_destroy):  Rename to...
	(Init::_S_ios_destroy_buffers):  this.
	(Init::Init):  Only construct streams once.
	(Init::~Init):  Flush streams, don't destroy them.
	(ios_base::sync_with_stdio):  Don't destroy streams, only buffers.
	* testsuite/27_io/ios_base/sync_with_stdio/9523.cc:  New test.
	* testsuite/27_io/objects/char/5.cc:  New test.
	* testsuite/27_io/objects/char/5268.cc:  Avoid undefined behavior.
	* testsuite/27_io/objects/char/6.cc:  New test.
	* testsuite/27_io/objects/char/7.cc:  New test.


Index: libstdc++-v3/include/bits/ios_base.h
===================================================================
RCS file: /home/petur/cvsroot/gcc/libstdc++-v3/include/bits/ios_base.h,v
retrieving revision 1.1.1.3
diff -c -3 -p -r1.1.1.3 ios_base.h
*** libstdc++-v3/include/bits/ios_base.h	12 Mar 2003 22:29:33 -0000	1.1.1.3
--- libstdc++-v3/include/bits/ios_base.h	26 Apr 2003 09:41:33 -0000
*************** namespace std
*** 453,462 ****
        ~Init();
        
        static void
!       _S_ios_create(bool __sync);
        
        static void
!       _S_ios_destroy();
  
        // NB: Allows debugger applications use of the standard streams
        // from operator new. _S_ios_base_init must be incremented in
--- 453,468 ----
        ~Init();
        
        static void
!       _S_ios_create_streams();
! 
!       static void
!       _S_ios_flush();
! 
!       static void
!       _S_ios_create_buffers(bool __sync);
        
        static void
!       _S_ios_destroy_buffers();
  
        // NB: Allows debugger applications use of the standard streams
        // from operator new. _S_ios_base_init must be incremented in
Index: libstdc++-v3/src/ios.cc
===================================================================
RCS file: /home/petur/cvsroot/gcc/libstdc++-v3/src/ios.cc,v
retrieving revision 1.1.1.4
diff -c -3 -p -r1.1.1.4 ios.cc
*** libstdc++-v3/src/ios.cc	24 Apr 2003 19:58:52 -0000	1.1.1.4
--- libstdc++-v3/src/ios.cc	26 Apr 2003 12:49:28 -0000
*************** namespace std 
*** 154,192 ****
    { return _M_name; }
  
    void
!   ios_base::Init::_S_ios_create(bool __sync)
    {
      size_t __out_size = __sync ? 0 : static_cast<size_t>(BUFSIZ);
      size_t __in_size = __sync ? 1 : static_cast<size_t>(BUFSIZ);
  
!     // NB: The file globals.cc creates the four standard files
!     // with NULL buffers. At this point, we swap out the dummy NULL
!     // [io]stream objects and buffers with the real deal.
      new (&buf_cout) stdio_filebuf<char>(stdout, ios_base::out, __out_size);
      new (&buf_cin) stdio_filebuf<char>(stdin, ios_base::in, __in_size);
      new (&buf_cerr) stdio_filebuf<char>(stderr, ios_base::out, __out_size);
!     new (&cout) ostream(&buf_cout);
!     new (&cin) istream(&buf_cin);
!     new (&cerr) ostream(&buf_cerr);
!     new (&clog) ostream(&buf_cerr);
!     cin.tie(&cout);
!     cerr.flags(ios_base::unitbuf);
      
  #ifdef _GLIBCPP_USE_WCHAR_T
      new (&buf_wcout) stdio_filebuf<wchar_t>(stdout, ios_base::out, __out_size);
      new (&buf_wcin) stdio_filebuf<wchar_t>(stdin, ios_base::in, __in_size);
      new (&buf_wcerr) stdio_filebuf<wchar_t>(stderr, ios_base::out, __out_size);
!     new (&wcout) wostream(&buf_wcout);
!     new (&wcin) wistream(&buf_wcin);
!     new (&wcerr) wostream(&buf_wcerr);
!     new (&wclog) wostream(&buf_wcerr);
!     wcin.tie(&wcout);
!     wcerr.flags(ios_base::unitbuf);
  #endif
    }
  
    void
!   ios_base::Init::_S_ios_destroy()
    {
      // Explicitly call dtors to free any memory that is dynamically
      // allocated by filebuf ctor or member functions, but don't
--- 154,209 ----
    { return _M_name; }
  
    void
!   ios_base::Init::_S_ios_create_streams()
!   {
!     // The standard streams are constructed once only and never destroyed.
!     // The stream buffers are set in _S_ios_create_buffers below.
!     new (&cout) ostream(NULL);
!     new (&cin) istream(NULL);
!     new (&cerr) ostream(NULL);
!     new (&clog) ostream(NULL);
!     cin.tie(&cout);
!     cerr.flags(ios_base::unitbuf);
!     
! #ifdef _GLIBCPP_USE_WCHAR_T
!     new (&wcout) wostream(NULL);
!     new (&wcin) wistream(NULL);
!     new (&wcerr) wostream(NULL);
!     new (&wclog) wostream(NULL);
!     wcin.tie(&wcout);
!     wcerr.flags(ios_base::unitbuf);
! #endif
!   }
! 
!   void
!   ios_base::Init::_S_ios_create_buffers(bool __sync)
    {
      size_t __out_size = __sync ? 0 : static_cast<size_t>(BUFSIZ);
      size_t __in_size = __sync ? 1 : static_cast<size_t>(BUFSIZ);
  
!     // Create stream buffers for the standard streams and use those
!     // buffers without destroying and recreating the streams.
      new (&buf_cout) stdio_filebuf<char>(stdout, ios_base::out, __out_size);
      new (&buf_cin) stdio_filebuf<char>(stdin, ios_base::in, __in_size);
      new (&buf_cerr) stdio_filebuf<char>(stderr, ios_base::out, __out_size);
!     cout.rdbuf(&buf_cout);
!     cin.rdbuf(&buf_cin);
!     cerr.rdbuf(&buf_cerr);
!     clog.rdbuf(&buf_cerr);
      
  #ifdef _GLIBCPP_USE_WCHAR_T
      new (&buf_wcout) stdio_filebuf<wchar_t>(stdout, ios_base::out, __out_size);
      new (&buf_wcin) stdio_filebuf<wchar_t>(stdin, ios_base::in, __in_size);
      new (&buf_wcerr) stdio_filebuf<wchar_t>(stderr, ios_base::out, __out_size);
!     wcout.rdbuf(&buf_wcout);
!     wcin.rdbuf(&buf_wcin);
!     wcerr.rdbuf(&buf_wcerr);
!     wclog.rdbuf(&buf_wcerr);
  #endif
    }
  
    void
!   ios_base::Init::_S_ios_destroy_buffers()
    {
      // Explicitly call dtors to free any memory that is dynamically
      // allocated by filebuf ctor or member functions, but don't
*************** namespace std 
*** 202,222 ****
  #endif
    }
  
    ios_base::Init::Init()
    {
      if (_S_ios_base_init == 0)
        {
  	// Standard streams default to synced with "C" operations.
  	ios_base::Init::_S_synced_with_stdio = true;
! 	_S_ios_create(ios_base::Init::_S_synced_with_stdio);
        }
      ++_S_ios_base_init;
    }
  
    ios_base::Init::~Init()
    {
!     if (--_S_ios_base_init == 0)
!       _S_ios_destroy();
    } 
  
    // 27.4.2.5  ios_base storage functions
--- 219,262 ----
  #endif
    }
  
+   void
+   ios_base::Init::_S_ios_flush()
+   {
+     // Flush standard output streams as required by 27.4.2.1.6
+     cout.flush();
+     cerr.flush();
+     clog.flush();
+ 
+ #ifdef _GLIBCPP_USE_WCHAR_T
+     wcout.flush();
+     wcerr.flush();
+     wclog.flush();    
+ #endif
+   }
+ 
    ios_base::Init::Init()
    {
      if (_S_ios_base_init == 0)
        {
  	// Standard streams default to synced with "C" operations.
  	ios_base::Init::_S_synced_with_stdio = true;
! 	_S_ios_create_streams();
! 	_S_ios_create_buffers(ios_base::Init::_S_synced_with_stdio);
! 	_S_ios_base_init = 1;
        }
      ++_S_ios_base_init;
    }
  
    ios_base::Init::~Init()
    {
!     if (--_S_ios_base_init == 1)
!       {
! 	// Catch any exceptions thrown by basic_ostream::flush()
! 	try
! 	  { _S_ios_flush(); }
! 	catch (...)
! 	  { }
!       }
    } 
  
    // 27.4.2.5  ios_base storage functions
*************** namespace std 
*** 356,363 ****
      if (!__sync && __ret)
        {
  	ios_base::Init::_S_synced_with_stdio = false;
! 	ios_base::Init::_S_ios_destroy();
! 	ios_base::Init::_S_ios_create(ios_base::Init::_S_synced_with_stdio);
        }
      return __ret; 
    }
--- 396,403 ----
      if (!__sync && __ret)
        {
  	ios_base::Init::_S_synced_with_stdio = false;
! 	ios_base::Init::_S_ios_destroy_buffers();
! 	ios_base::Init::_S_ios_create_buffers(false);
        }
      return __ret; 
    }
Index: libstdc++-v3/testsuite/27_io/ios_base/sync_with_stdio/9523.cc
===================================================================
RCS file: libstdc++-v3/testsuite/27_io/ios_base/sync_with_stdio/9523.cc
diff -N libstdc++-v3/testsuite/27_io/ios_base/sync_with_stdio/9523.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libstdc++-v3/testsuite/27_io/ios_base/sync_with_stdio/9523.cc	26 Apr 2003 08:37:58 -0000
***************
*** 0 ****
--- 1,51 ----
+ // 2003-04-26 Petur Runolfsson  <peturr02 at ru dot is>
+ 
+ // Copyright (C) 2003 Free Software Foundation
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This 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 General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 27.4.2.4 ios_base static members
+ 
+ #include <testsuite_hooks.h>
+ #include <iostream>
+ 
+ // libstdc++/9523
+ void test01()
+ {
+   using namespace std;
+ 
+   int index = ios_base::xalloc();
+ 
+   cin.iword(index) = 5;
+   cout.iword(index) = 6;
+   cerr.iword(index) = 7;
+   clog.iword(index) = 8;
+ 
+   ios_base::sync_with_stdio(false);
+ 
+   VERIFY( cin.iword(index) == 5 );
+   VERIFY( cout.iword(index) == 6 );
+   VERIFY( cerr.iword(index) == 7 );
+   VERIFY( clog.iword(index) == 8 );
+ }
+ 
+ int main()
+ {
+   test01();
+   return 0;
+ }
+ 
Index: libstdc++-v3/testsuite/27_io/objects/char/5.cc
===================================================================
RCS file: libstdc++-v3/testsuite/27_io/objects/char/5.cc
diff -N libstdc++-v3/testsuite/27_io/objects/char/5.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libstdc++-v3/testsuite/27_io/objects/char/5.cc	26 Apr 2003 12:23:52 -0000
***************
*** 0 ****
--- 1,85 ----
+ // 2003-04-26 Petur Runolfsson  <peturr02 at ru dot is>
+ 
+ // Copyright (C) 2003 Free Software Foundation
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This 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 General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 27.3 Standard iostream objects
+ 
+ // Check that standard streams can be used from constructors and
+ // destructors of static objects, provided that an instance of 
+ // ios_base::Init has been constructed.
+ 
+ void init_standard_streams();
+ int use_standard_streams();
+ 
+ struct Strange
+ {
+   int i;
+ 
+   Strange()
+   {
+     init_standard_streams();
+     i = use_standard_streams();
+   }
+ 
+   ~Strange()
+   {
+     use_standard_streams();
+     init_standard_streams();
+   }
+ };
+ 
+ static Strange static_ob;
+ 
+ #include <testsuite_hooks.h>
+ #include <iostream>
+ 
+ void init_standard_streams()
+ {
+   std::ios_base::Init init;
+ }
+ 
+ int use_standard_streams()
+ {
+   std::cout << "Hello, world!" << std::endl;
+   std::cerr << "World, hello!" << std::endl;
+ 
+   int ret = std::ios_base::xalloc();
+   std::cin.iword(ret) = ret + 1;
+   std::cout.iword(ret) = ret + 2;
+   std::cerr.iword(ret) = ret + 3;
+   std::clog.iword(ret) = ret + 4;
+   return ret;
+ }
+ 
+ void test05()
+ {
+   bool test = true;
+   int i = static_ob.i;
+ 
+   VERIFY( std::cin.iword(i) == i + 1 );
+   VERIFY( std::cout.iword(i) == i + 2 );
+   VERIFY( std::cerr.iword(i) == i + 3 );
+   VERIFY( std::clog.iword(i) == i + 4 );
+ }
+ 
+ int main()
+ {
+   test05();
+   return 0;
+ }
Index: libstdc++-v3/testsuite/27_io/objects/char/5268.cc
===================================================================
RCS file: /home/petur/cvsroot/gcc/libstdc++-v3/testsuite/27_io/objects/char/5268.cc,v
retrieving revision 1.1.1.1
diff -c -3 -p -r1.1.1.1 5268.cc
*** libstdc++-v3/testsuite/27_io/objects/char/5268.cc	24 Apr 2003 19:59:13 -0000	1.1.1.1
--- libstdc++-v3/testsuite/27_io/objects/char/5268.cc	26 Apr 2003 09:47:10 -0000
*************** void test04()
*** 36,41 ****
--- 36,42 ----
    std::stringbuf b1;
    std::cout.rdbuf( &b1 );
    std::cout << "hello\n";
+   std::cout.rdbuf(NULL);
  }
  
  int main()
Index: libstdc++-v3/testsuite/27_io/objects/char/6.cc
===================================================================
RCS file: libstdc++-v3/testsuite/27_io/objects/char/6.cc
diff -N libstdc++-v3/testsuite/27_io/objects/char/6.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libstdc++-v3/testsuite/27_io/objects/char/6.cc	26 Apr 2003 10:05:19 -0000
***************
*** 0 ****
--- 1,50 ----
+ // 2003-04-26 Petur Runolfsson  <peturr02 at ru dot is>
+ 
+ // Copyright (C) 2003 Free Software Foundation
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This 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 General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 27.3 Standard iostream objects
+ 
+ // ios_base::Init::~Init() calls cout.flush(), which may call
+ // cout.setstate(badbit), which may throw an exception. Check that
+ // the exception doesn't escape from the destructor.
+ 
+ #include <iostream>
+ #include <streambuf>
+ 
+ class Badbuf : public std::streambuf
+ {
+ protected:
+   virtual int sync()
+   {
+     return -1;
+   }
+ };
+ 
+ void test06()
+ {
+   std::ios_base::Init init;
+   std::cout.rdbuf(new Badbuf);
+   std::cout.exceptions(std::ios_base::badbit);
+ }
+ 
+ int main()
+ {
+   test06();
+   return 0;
+ }
Index: libstdc++-v3/testsuite/27_io/objects/char/7.cc
===================================================================
RCS file: libstdc++-v3/testsuite/27_io/objects/char/7.cc
diff -N libstdc++-v3/testsuite/27_io/objects/char/7.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libstdc++-v3/testsuite/27_io/objects/char/7.cc	26 Apr 2003 11:00:52 -0000
***************
*** 0 ****
--- 1,75 ----
+ // 2003-04-26 Petur Runolfsson  <peturr02 at ru dot is>
+ 
+ // Copyright (C) 2003 Free Software Foundation, Inc.
+ //
+ // This file is part of the GNU ISO C++ Library.  This library is free
+ // software; you can redistribute it and/or modify it under the
+ // terms of the GNU General Public License as published by the
+ // Free Software Foundation; either version 2, or (at your option)
+ // any later version.
+ 
+ // This 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 General Public License for more details.
+ 
+ // You should have received a copy of the GNU General Public License along
+ // with this library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // 27.3 Standard iostream objects
+ 
+ #include <fstream>
+ #include <iostream>
+ #include <unistd.h>
+ #include <signal.h>
+ #include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <testsuite_hooks.h>
+ 
+ // Check that cout.flush() is called when last ios_base::Init is destroyed.
+ void test07()
+ {
+   using namespace std;
+   bool test = true;
+ 
+   const char* name = "tmp_fifo4";
+ 
+   signal(SIGPIPE, SIG_IGN);
+ 
+   unlink(name);  
+   mkfifo(name, S_IRWXU);
+   
+   int child = fork();
+   VERIFY( child != -1 );
+ 
+   if (child == 0)
+     {
+       filebuf fbout;
+       sleep(1);
+       fbout.open(name, ios_base::out);
+       cout.rdbuf(&fbout);
+       fbout.sputc('a');
+       sleep(2);
+       // NB: fbout is *not* destroyed here!
+       exit(0);
+     }
+   
+   filebuf fbin;
+   fbin.open(name, ios_base::in);
+   sleep(2);
+   filebuf::int_type c = fbin.sbumpc();
+   VERIFY( c != filebuf::traits_type::eof() );
+   VERIFY( c == filebuf::traits_type::to_int_type('a') );
+ 
+   fbin.close();
+ }
+ 
+ int
+ main()
+ {
+   test07();
+   return 0;
+ }


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