<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 1183: basic_ios::set_rdbuf may break class invariants</title>
<meta property="og:title" content="Issue 1183: basic_ios::set_rdbuf may break class invariants">
<meta property="og:description" content="C++ library issue. Status: C++11">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue1183.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++11">C++11</a> status.</em></p>
<h3 id="1183"><a href="lwg-defects.html#1183">1183</a>. <code>basic_ios::set_rdbuf</code> may break class invariants</h3>
<p><b>Section:</b> 31.5.4.3 <a href="https://wg21.link/basic.ios.members">[basic.ios.members]</a> <b>Status:</b> <a href="lwg-active.html#C++11">C++11</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2009-07-28 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#basic.ios.members">issues</a> in [basic.ios.members].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++11">C++11</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The protected member function <code>set_rdbuf</code> had been added during the
process of adding move and swap semantics to IO classes. A relevant
property of this function is described by it's effects in
31.5.4.3 <a href="https://wg21.link/basic.ios.members">[basic.ios.members]</a>/19:
</p>

<blockquote><p>
<i>Effects:</i> Associates the <code>basic_streambuf</code> object pointed to by sb with
this stream without calling <code>clear()</code>.
</p></blockquote>

<p>
This means that implementors of or those who derive from existing IO classes
could cause an internal state where the stream buffer could be 0, but the
IO class has the state <code>good()</code>. This would break several currently existing
implementations which rely on the fact that setting a stream buffer via the
currently only ways, i.e. either by calling
</p>

<blockquote><pre>
void init(basic_streambuf&lt;charT,traits&gt;* sb);
</pre></blockquote>

<p>
or by calling
</p>

<blockquote><pre>
basic_streambuf&lt;charT,traits&gt;* rdbuf(basic_streambuf&lt;charT,traits&gt;* sb);
</pre></blockquote>

<p>
to set <code>rdstate()</code> to <code>badbit</code>, if the buffer is 0. This has the effect that many
internal functions can simply check <code>rdstate()</code> instead of <code>rdbuf()</code> for being 0.
</p>

<p>
I therefore suggest that a requirement is added for callers of <code>set_rdbuf</code> to
set a non-0 value.
</p>

<p><i>[
2009-10 Santa Cruz:
]</i></p>


<blockquote><p>
Moved to Open.  Martin volunteers to provide new wording, where
<code>set_rdbuf()</code> sets the <code>badbit</code> but does not cause an
exception to be thrown like a call to <code>clear()</code> would.
</p></blockquote>

<p><i>[
2009-10-20 Martin provides wording:
]</i></p>


<p>
Change 31.5.4.3 <a href="https://wg21.link/basic.ios.members">[basic.ios.members]</a> around p. 19 as indicated:
</p>

<blockquote><pre>
void set_rdbuf(basic_streambuf&lt;charT, traits&gt;* sb);
</pre>

<blockquote>
<p><del>
<i>Effects:</i> Associates the <code>basic_streambuf</code> object pointed
to by <code>sb</code> with this stream without calling <code>clear()</code>.
<i>Postconditions:</i> <code>rdbuf() == sb</code>.
</del></p>

<p><ins>
<i>Effects:</i> As if:
</ins></p>

<blockquote><pre><ins>
iostate state = rdstate();
try { rdbuf(sb); }
catch(ios_base::failure) {
   if (0 == (state &amp; ios_base::badbit))
       unsetf(badbit);
}
</ins></pre></blockquote>

<p>
<i>Throws:</i> Nothing.
</p>

</blockquote>
</blockquote>

<p><b>Rationale:</b></p><p>
We need to be able to call <code>set_rdbuf()</code> on stream objects
for which (<code>rdbuf() == 0</code>) holds without causing <code>ios_base::failure</code> to
be thrown. We also don't want <code>badbit</code> to be set as a result of
setting <code>rdbuf()</code> to 0 if it wasn't set before the call. This changed
Effects clause maintains the current behavior (as of N2914) without
requiring that <code>sb</code> be non-null.
</p>

<p><i>[
Post-Rapperswil
]</i></p>


<p>
Several reviewers and the submitter believe that the best solution would be to add a pre-condition that the 
buffer shall not be a null pointer value.
</p>

<blockquote><p>
Moved to Tentatively Ready with revised wording provided by Daniel after 5 positive votes on c++std-lib.
</p></blockquote>

<p><i>[
Adopted at 2010-11 Batavia
]</i></p>




<p id="res-1183"><b>Proposed resolution:</b></p>
<ol>
<li>Add a new pre-condition just before 27.5.4.2 [basic.ios.members]/23 as indicated:
<blockquote><pre>
void set_rdbuf(basic_streambuf&lt;charT, traits&gt;* sb);
</pre>
<blockquote><p>
<ins>?? <em>Requires</em>: <code>sb != nullptr</code>.</ins>
<p/>
23 <em>Effects</em>: Associates the <code>basic_streambuf</code> object pointed to by <code>sb</code> with this stream without calling <code>clear()</code>.
</p>
<p>
24 <em>Postconditions</em>: <code>rdbuf() == sb</code>.
</p>
<p>
25 <em>Throws</em>: Nothing.
</p>
</blockquote></blockquote>
</li>
</ol>


<p><b>Rationale:</b></p><p>
We believe that setting a <code>nullptr</code> stream buffer can be prevented.
</p>




</body>
</html>
