On 23/09/17 09:54 +0300, Petr Ovtchenkov wrote:
istreambuf_iterator should not forget about attached
streambuf when it reach EOF.

Checks in debug mode has no infuence more on character
extraction in istreambuf_iterator increment operators.
In this aspect behaviour in debug and non-debug mode
is similar now.

Test for detached srteambuf in istreambuf_iterator:
When istreambuf_iterator reach EOF of istream, it should not
forget about attached streambuf.
From fact "EOF in stream reached" not follow that
stream reach end of life and input operation impossible
more.
---
libstdc++-v3/include/bits/streambuf_iterator.h     | 41 +++++++--------
.../24_iterators/istreambuf_iterator/3.cc          | 61 ++++++++++++++++++++++
2 files changed, 80 insertions(+), 22 deletions(-)
create mode 100644 libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc

diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h 
b/libstdc++-v3/include/bits/streambuf_iterator.h
index f0451b1..45c3d89 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -136,12 +136,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      istreambuf_iterator&
      operator++()
      {
-       __glibcxx_requires_cond(!_M_at_eof(),
+       __glibcxx_requires_cond(_M_sbuf,
                                _M_message(__gnu_debug::__msg_inc_istreambuf)
                                ._M_iterator(*this));
        if (_M_sbuf)
          {
+#ifdef _GLIBCXX_DEBUG_PEDANTIC
+           int_type _tmp =
+#endif
            _M_sbuf->sbumpc();
+#ifdef _GLIBCXX_DEBUG_PEDANTIC
+           
__glibcxx_requires_cond(!traits_type::eq_int_type(_tmp,traits_type::eof()),
+                                   
_M_message(__gnu_debug::__msg_inc_istreambuf)
+                                   ._M_iterator(*this));
+#endif
            _M_c = traits_type::eof();
          }
        return *this;
@@ -151,14 +159,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      istreambuf_iterator
      operator++(int)
      {
-       __glibcxx_requires_cond(!_M_at_eof(),
+        _M_get();
+       __glibcxx_requires_cond(_M_sbuf
+                               && 
!traits_type::eq_int_type(_M_c,traits_type::eof()),
                                _M_message(__gnu_debug::__msg_inc_istreambuf)
                                ._M_iterator(*this));

        istreambuf_iterator __old = *this;
        if (_M_sbuf)
          {
-           __old._M_c = _M_sbuf->sbumpc();
+           _M_sbuf->sbumpc();
            _M_c = traits_type::eof();
          }
        return __old;
@@ -177,18 +187,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      _M_get() const
      {
        const int_type __eof = traits_type::eof();
-       int_type __ret = __eof;
-       if (_M_sbuf)
-         {
-           if (!traits_type::eq_int_type(_M_c, __eof))
-             __ret = _M_c;
-           else if (!traits_type::eq_int_type((__ret = _M_sbuf->sgetc()),
-                                              __eof))
-             _M_c = __ret;
-           else
-             _M_sbuf = 0;
-         }
-       return __ret;
+       if (_M_sbuf && traits_type::eq_int_type(_M_c, __eof))
+          _M_c = _M_sbuf->sgetc();
+       return _M_c;
      }

      bool
@@ -339,7 +340,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      typedef typename __is_iterator_type::streambuf_type  streambuf_type;
      typedef typename traits_type::int_type               int_type;

-      if (__first._M_sbuf && !__last._M_sbuf)
+      if (__first._M_sbuf && (__last == istreambuf_iterator<_CharT>()))
        {
          streambuf_type* __sb = __first._M_sbuf;
          int_type __c = __sb->sgetc();
@@ -374,7 +375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      typedef typename __is_iterator_type::streambuf_type  streambuf_type;
      typedef typename traits_type::int_type               int_type;

-      if (__first._M_sbuf && !__last._M_sbuf)
+      if (__first._M_sbuf && (__last == istreambuf_iterator<_CharT>()))
        {
          const int_type __ival = traits_type::to_int_type(__val);
          streambuf_type* __sb = __first._M_sbuf;
@@ -395,11 +396,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
              else
                __c = __sb->snextc();
            }
-
-         if (!traits_type::eq_int_type(__c, traits_type::eof()))
-           __first._M_c = __c;
-         else
-           __first._M_sbuf = 0;
+         __first._M_c = __c;
        }
      return __first;
    }
diff --git a/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc 
b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc
new file mode 100644
index 0000000..803ede4
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/3.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++17" }
+
+// Copyright (C) 2017 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 3, 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 COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <algorithm>
+#include <sstream>
+#include <iterator>
+#include <cstring>
+#include <testsuite_hooks.h>
+
+void test03()
+{
+  using namespace std;
+  bool test __attribute__((unused)) = true;
+
+  std::stringstream s;
+  char b[] = "c2ee3d09-43b3-466d-b490-db35999a22cf";
+  char r[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+  char q[] = "3c4852d6-d47b-4f46-b05e-b5edc1aa440e";
+  //          012345678901234567890123456789012345
+  //          0         1         2         3
+  s << b;
+  VERIFY( !s.fail() );
+
+  istreambuf_iterator<char> i(s);
+  copy_n(i, 36, r);
+  ++i; // EOF reached
+  VERIFY(i == std::istreambuf_iterator<char>());
+
+  VERIFY(memcmp(b, r, 36) == 0);
+
+  s << q;
+  VERIFY(!s.fail());
+
+  copy_n(i, 36, r);

This is undefined behaviour. The end-of-stream iterator value cannot
be dereferenced.

Reply via email to