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/RFC] Fix libstdc++/9533


Hi,

the below fixes the problem by implementing a non-trivial showmanyc(),
as discussed thoroughly on the list during the last weeks.

Tested x86-linux.

In particular, I would appreciate by reassured that the new
__basic_file<>::showmanyc_helper deals correctly with the various
possibilities.

Thanks,
Paolo.

//////////
2003-03-13  Paolo Carlini  <pcarlini at unitus dot it>
            Nathan Myers <ncm at cantrip dot org>

	PR libstdc++/9533
	* include/bits/fstream.tcc (basic_filebuf<>::open): Don't
	call underflow().
	(basic_filebuf<>::showmanyc): Use the information provided
	by codecvt and __basic_file<>::showmanyc_helper to implement
	a non-trivial showmanyc.
	* config/io/basic_file_stdio.h
	(__basic_file<>::showmanyc_helper): New, declare.
	* config/io/basic_file_stdio.cc
	(__basic_file<>::showmanyc_helper): Define.
	(__basic_file<>::_M_open_mode): Don't set O_NONBLOCK.
	(__basic_file<char>::open): Don't call fcntl().
	* acinclude.m4 (GLIBCPP_CHECK_S_ISREG, GLIBCPP_CHECK_S_IFREG
	GLIBCPP_CHECK_RECV_PEEK_SAFE): New macros.
	* configure.in: Call here.
	* acconfig.h: Add #undefs for the corresponding symbols.
	* aclocal.m4: Regenerate.
	* configure: Regenerate.
	* config.h.in: Regenerate.
	* testsuite/27_io/filebuf_virtuals.cc (test16, test17): Add.
	
diff -urN libstdc++-v3-orig/acconfig.h libstdc++-v3/acconfig.h
--- libstdc++-v3-orig/acconfig.h	2002-11-13 23:49:20.000000000 +0100
+++ libstdc++-v3/acconfig.h	2003-03-13 02:17:25.000000000 +0100
@@ -138,6 +138,15 @@
 // Define if LC_MESSAGES is available in <locale.h>.
 #undef HAVE_LC_MESSAGES
 
+// Define if S_ISREG (Posix) is available in <sys/stat.h>.
+#undef HAVE_S_ISREG
+
+// Define if S_IFREG is available in <sys/stat.h>.
+#undef HAVE_S_IFREG
+
+// Define if recv(0, 0, 0, (MSG_DONTWAIT|MSG_PEEK)) can be used.
+#undef HAVE_RECV_PEEK_SAFE
+
 // Define if <float.h> exists.
 #undef HAVE_FLOAT_H
 
diff -urN libstdc++-v3-orig/acinclude.m4 libstdc++-v3/acinclude.m4
--- libstdc++-v3-orig/acinclude.m4	2003-03-09 23:55:03.000000000 +0100
+++ libstdc++-v3/acinclude.m4	2003-03-13 02:16:37.000000000 +0100
@@ -2124,6 +2124,53 @@
   ])
 ])
 
+dnl
+dnl Check whether S_ISREG (Posix) is available in <sys/stat.h>.
+dnl
+
+AC_DEFUN(GLIBCPP_CHECK_S_ISREG, [
+  AC_CACHE_VAL(glibcpp_cv_S_ISREG, [
+    AC_TRY_LINK([#include <sys/stat.h>],
+                [struct stat buffer; fstat(0, &buffer); S_ISREG(buffer.st_mode); ],
+                [glibcpp_cv_S_ISREG=yes],
+                [glibcpp_cv_S_ISREG=no])
+  ])
+  if test $glibcpp_cv_S_ISREG = yes; then
+    AC_DEFINE(HAVE_S_ISREG)
+  fi
+])
+
+dnl
+dnl Check whether S_IFREG is available in <sys/stat.h>.
+dnl
+
+AC_DEFUN(GLIBCPP_CHECK_S_IFREG, [
+  AC_CACHE_VAL(glibcpp_cv_S_IFREG, [
+    AC_TRY_LINK([#include <sys/stat.h>],
+                [struct stat buffer; fstat(0, &buffer); S_IFREG(buffer.st_mode); ],
+                [glibcpp_cv_S_IFREG=yes],
+                [glibcpp_cv_S_IFREG=no])
+  ])
+  if test $glibcpp_cv_S_IFREG = yes; then
+    AC_DEFINE(HAVE_S_IFREG)
+  fi
+])
+
+dnl
+dnl Check whether recv(0, 0, 0, (MSG_DONTWAIT|MSG_PEEK)) can be used.
+dnl
+
+AC_DEFUN(GLIBCPP_CHECK_RECV_PEEK_SAFE, [
+  AC_CACHE_VAL(glibcpp_cv_RECV_PEEK_SAFE, [
+    AC_TRY_LINK([#include <sys/socket.h>],
+                [recv(0, 0, 0, (MSG_DONTWAIT|MSG_PEEK)); ],
+                [glibcpp_cv_RECV_PEEK_SAFE=yes],
+                [glibcpp_cv_RECV_PEEK_SAFE=no])
+  ])
+  if test $glibcpp_cv_RECV_PEEK_SAFE = yes; then
+    AC_DEFINE(HAVE_RECV_PEEK_SAFE)
+  fi
+])
 
 dnl
 dnl Check for whether the Boost-derived checks should be turned on.
diff -urN libstdc++-v3-orig/config/io/basic_file_stdio.cc libstdc++-v3/config/io/basic_file_stdio.cc
--- libstdc++-v3-orig/config/io/basic_file_stdio.cc	2003-03-10 07:49:40.000000000 +0100
+++ libstdc++-v3/config/io/basic_file_stdio.cc	2003-03-13 02:20:24.000000000 +0100
@@ -35,6 +35,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
 
 namespace std 
 {
@@ -76,11 +78,7 @@
     if (__testi && !__testo && !__testt && !__testa)
       {
 	strcpy(__c_mode, "r");
-#if defined (O_NONBLOCK)
-	__p_mode |=  O_RDONLY | O_NONBLOCK;
-#else
 	__p_mode |=  O_RDONLY;
-#endif
       }
     if (__testi && __testo && !__testt && !__testa)
       {
@@ -156,13 +154,6 @@
 	if ((_M_cfile = fopen(__name, __c_mode)))
 	  {
 	    _M_cfile_created = true;
-
-#if defined (F_SETFL) && defined (O_NONBLOCK)
-	    // Set input to nonblocking for fifos.
-	    if (__mode & ios_base::in)
-	      fcntl(this->fd(), F_SETFL, O_NONBLOCK);
-#endif
-
 	    __ret = this;
 	  }
       }
@@ -261,4 +252,39 @@
   int 
   __basic_file<char>::sync() 
   { return fflush(_M_cfile); }
+
+  streamsize
+  __basic_file<char>::showmanyc_helper(bool __stdio)
+  {
+#ifdef _GLIBCPP_HAVE_RECV_PEEK_SAFE 
+    // Pipes.
+    streamsize __size =
+      recv(this->fd(), 0, 0, (MSG_DONTWAIT|MSG_PEEK));
+    if (__size >= 0)
+      return __size;
+#endif
+
+#ifdef _GLIBCPP_HAVE_S_ISREG
+    // Regular files.
+    struct stat __buffer;
+    int __ret = fstat(this->fd(), &__buffer);
+    if (!__ret && S_ISREG(__buffer.st_mode))
+      if (__stdio)
+	return __buffer.st_size - ftell(_M_cfile);
+      else
+	return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur);
+#elif _GLIBCPP_HAVE_S_IFREG
+    // Regular files.
+    struct stat __buffer;
+    int __ret = fstat(this->fd(), &__buffer);
+    if (!__ret && S_IFREG(__buffer.st_mode))
+      if (__stdio)
+	return __buffer.st_size - ftell(_M_cfile);
+      else
+	return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur);
+#endif
+
+    return 0;
+  }
+
 }  // namespace std
diff -urN libstdc++-v3-orig/config/io/basic_file_stdio.h libstdc++-v3/config/io/basic_file_stdio.h
--- libstdc++-v3-orig/config/io/basic_file_stdio.h	2003-03-09 23:55:04.000000000 +0100
+++ libstdc++-v3/config/io/basic_file_stdio.h	2003-03-11 22:44:03.000000000 +0100
@@ -108,6 +108,9 @@
 
       int 
       sync();
+
+      streamsize
+      showmanyc_helper(bool __stdio);
     };
 }  // namespace std

diff -urN libstdc++-v3-orig/include/bits/fstream.tcc libstdc++-v3/include/bits/fstream.tcc
--- libstdc++-v3-orig/include/bits/fstream.tcc	2003-03-09 23:55:04.000000000 +0100
+++ libstdc++-v3/include/bits/fstream.tcc	2003-03-13 13:19:29.000000000 +0100
@@ -96,13 +96,6 @@
 	      // Setup initial position of buffer.
 	      _M_set_indeterminate();
 
-	      // Set input buffer to something real.
-	      // NB: Must open in non-blocking way to do this, or must
-	      // set the initial position in a different manner than
-	      // using underflow.
- 	      if (__mode & ios_base::in && _M_buf_allocated)
- 		this->underflow();
-
 	      if ((__mode & ios_base::ate)
 		  && this->seekoff(0, ios_base::end, __mode) < 0)
 		{
@@ -161,9 +154,21 @@
     {
       streamsize __ret = -1;
       bool __testin = this->_M_mode & ios_base::in;
+      const locale __loc = this->getloc();
+      const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
+      // Sync with stdio.
+      bool __sync = this->_M_buf_size == 1;
 
       if (__testin && this->is_open())
-	__ret = this->_M_in_end - this->_M_in_cur;
+	{
+	  __ret = this->_M_in_end - this->_M_in_cur;
+
+	  // For a stateful encoding (-1) the pending sequence might be just
+	  // shift and unshift prefixes with no actual character.
+	  if (__cvt.encoding() >= 0)
+	    __ret += _M_file.showmanyc_helper(__sync) / __cvt.max_length();
+	}
+
       _M_last_overflowed = false;	
       return __ret;
     }
diff -urN libstdc++-v3-orig/testsuite/27_io/filebuf_virtuals.cc libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc
--- libstdc++-v3-orig/testsuite/27_io/filebuf_virtuals.cc	2003-03-09 23:55:04.000000000 +0100
+++ libstdc++-v3/testsuite/27_io/filebuf_virtuals.cc	2003-03-13 10:50:13.000000000 +0100
@@ -22,6 +22,11 @@
 
 #include <fstream>
 #include <locale>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <testsuite_hooks.h>
 
 // @require@ %-*.tst %-*.txt
@@ -76,6 +81,7 @@
 const char name_06[] = "filebuf_virtuals-6.txt"; // empty file, need to create
 const char name_07[] = "filebuf_virtuals-7.txt"; // empty file, need to create
 const char name_08[] = "filebuf_virtuals-8.txt"; // empty file, need to create
+const char name_09[] = "filebuf_virtuals-9.txt"; // empty file, need to create
 
 class derived_filebuf: public std::filebuf
 {
@@ -797,6 +803,92 @@
   fbin.close();
 }
 
+// libstdc++/9533 <1>
+void test16()
+{
+  using namespace std;
+  bool test = true;
+
+  const int count = 10000;
+
+  signal(SIGPIPE, SIG_IGN);
+  unlink("xxx");
+  
+  if (0 != mkfifo("xxx", S_IRWXU))
+    {
+      VERIFY( false );
+    }
+  
+  int fval = fork();
+  if (fval == -1)
+    {
+      unlink("xxx");
+      VERIFY( false );
+    }
+  else if (fval == 0)
+    {
+      filebuf ofbuf;
+      ofbuf.open("xxx", ios_base::out);
+      VERIFY( ofbuf.is_open() );
+      sleep(1);
+
+      for (int i = 0; i < count; ++i)
+	ofbuf.sputc(i % 100);
+
+      ofbuf.pubsync();
+      sleep(1);
+      ofbuf.close();
+      exit(0);
+    }
+
+  filebuf ifbuf;
+  ifbuf.open("xxx", ios_base::in);
+  VERIFY( ifbuf.is_open() );
+
+  for (int j = 0; j < count; ++j)
+    {
+      filebuf::int_type c1 = ifbuf.sbumpc();
+      VERIFY( c1 == j % 100 );
+    }
+
+  filebuf::int_type c6 = ifbuf.sbumpc();
+  VERIFY( c6 == filebuf::traits_type::eof() );
+
+  sleep(2);
+  ifbuf.close();
+
+  unlink("xxx");
+}
+
+// libstdc++/9533 <2>
+void test17()
+{
+  using namespace std;
+  const char* strlit = "0123456789";
+  
+  filebuf fbout;
+  fbout.open(name_09, ios_base::out | ios_base::trunc);
+  int written = 0;
+  for (int i = 0; i < BUFSIZ; ++i)
+    written += fbout.sputn(strlit, 10);
+  fbout.close();
+  
+  ifstream in(name_09);
+  int ia;
+  int sum = 0;
+  bool gotsome;
+  do
+    {
+      char buf[100];
+      int n = in.readsome(buf, sizeof(buf));
+      ia = in.rdbuf()->in_avail();
+      gotsome = (n > 0);
+      sum += n;
+    }
+  while (gotsome);
+  VERIFY( sum == written );
+}
+
 main() 
 {
   test01();
@@ -816,5 +908,7 @@
   test13();
   test14();
   test15();
+  test16();
+  test17();
   return 0;
 }

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