<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>P1494R4: Partial program correctness</title>
  <style type="text/css">
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
  </style>
  <style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
  { position: relative; }
pre.numberSource a.sourceLine:empty
  { position: absolute; }
pre.numberSource a.sourceLine::before
  { content: attr(data-line-number);
    position: absolute; left: -5em; text-align: right; vertical-align: baseline;
    border: none; pointer-events: all;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <style type="text/css">
  div.del, section.del { background: #fcd; }
  div.ins, section.ins { background: #bfa; }
  .mv { background: #ddf; }
  s, .del { background: #ff8888; margin-right: 0.15ch; }
  u, .ins { background: #88ff88; }
  /* from https://stackoverflow.com/a/32456613 */
  div > blockquote, body > blockquote {
      display: list-item;
      list-style-type: "- ";
  }
  /* With a 3 em gutter and two columns, ANSI letter is 127 characters wide. */
  pre {
  		margin-left: 1.2em;
  }
  .tony {
    border-collapse: collapse;
  }
  .tony > tbody > tr {
    vertical-align: top;
  }
  tr.hr, tr.hr {
    border-bottom: thin solid #60a0b0;  /* relies on collapse */
  }
  </style>
</head>
<body>
<header>
<h1 class="title">P1494R4: Partial program correctness<!-- -*- c++-md -*- --></h1>
</header>
<p><em>Audience</em>: EWG; CWG; LEWG; SG22<br />
S. Davis Herring &lt;<a href="mailto:herring@lanl.gov">herring@lanl.gov</a>&gt;<br />
Los Alamos National Laboratory<br />
October 14, 2024</p>
<h1 id="history">History</h1>
<p>Since <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p1494r3.html">r3</a>:</p>
<ul>
<li>Rebased onto N4988</li>
<li>Made I/O automatically a checkpoint</li>
<li>Added missing erroneous behavior context</li>
<li>Added C cross reference for host environment</li>
<li>Removed outdated note</li>
<li>Clarified, simplified, and corrected wording</li>
</ul>
<p>Since <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1494r2.html">r2</a>:</p>
<ul>
<li>Rebased onto N4981</li>
<li>Required freestanding support, per LEWG review</li>
<li>Clarified implementability</li>
<li>Mentioned implicit checkpoint alternative</li>
</ul>
<p>Since <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1494r1.html">r1</a>:</p>
<ul>
<li>Discussed the preexisting problem of input dependence</li>
<li>Discussed interactions with other kinds of observable behavior</li>
<li>Discussed lack of debugger support</li>
<li>Fixed (preexisting) “first” in wording based on SG1 review</li>
</ul>
<p>Since <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1494r0.html">r0</a>:</p>
<ul>
<li>Made introduction explicitly independent of contracts</li>
<li>Fixed conditionals in example</li>
</ul>
<h1 id="problem">Problem</h1>
<p>Undefined behavior enables and extends many important optimizations (<em>e.g.</em>, simplifying signed integer arithmetic and dead-code elimination). The “time travel” aspect of such optimizations (explicitly authorized by [intro.abstract]/5) is surprising to many programmers in that it can sometimes eliminate tests meant to detect the invalid operation in question. In particular, consider</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="pp">#include</span><span class="im">&lt;cstdio&gt;</span></a>
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="pp">#include</span><span class="im">&lt;cstdlib&gt;</span></a>
<a class="sourceLine" id="cb1-3" data-line-number="3"></a>
<a class="sourceLine" id="cb1-4" data-line-number="4"><span class="at">static</span> <span class="dt">void</span> bad(<span class="at">const</span> <span class="dt">char</span> *msg) {</a>
<a class="sourceLine" id="cb1-5" data-line-number="5">  <span class="bu">std::</span>fputs(msg, stderr);</a>
<a class="sourceLine" id="cb1-6" data-line-number="6"><span class="pp">#ifdef DIE</span></a>
<a class="sourceLine" id="cb1-7" data-line-number="7">  <span class="bu">std::</span>abort();</a>
<a class="sourceLine" id="cb1-8" data-line-number="8"><span class="pp">#endif</span></a>
<a class="sourceLine" id="cb1-9" data-line-number="9">}</a>
<a class="sourceLine" id="cb1-10" data-line-number="10"></a>
<a class="sourceLine" id="cb1-11" data-line-number="11"><span class="dt">void</span> inc(<span class="dt">int</span> *p) {</a>
<a class="sourceLine" id="cb1-12" data-line-number="12">  <span class="cf">if</span>(!p) bad(<span class="st">&quot;Null!</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb1-13" data-line-number="13">  ++*p;</a>
<a class="sourceLine" id="cb1-14" data-line-number="14">}</a></code></pre></div>
<p>Without <code>-DDIE</code>, a conforming implementation can elide the test in <code>inc</code> entirely: <code>std::fputs</code> always returns, so any call <code>inc(nullptr)</code> is guaranteed to have undefined behavior and need not call <code>bad</code>. (Note that current implementations do not do so in this case.)</p>
<p>This issue came up again near the beginning of 2019 in the discussion of contracts:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb2-1" data-line-number="1"><span class="dt">void</span> f(<span class="dt">int</span> *p) [[<span class="at">expects:</span> <span class="at">p</span>]] [[<span class="at">expects:</span> *<span class="at">p</span>&lt;<span class="at">5</span>]];</a></code></pre></div>
<p>Discomfort with the idea that (with continuation mode “on”) the first <em>contract-attribute-specifier</em> might be elided because of the second was one of the motivations for the many late proposals to change (and eventually remove) contracts. <a href="http://wiki.edg.com/pub/Wg21sandiego2018/EvolutionWorkingGroup/p1343-contracts-update.html">Many</a> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1429r0.pdf#subsection.A.1">wondered</a> about the possibility of making a contract violation handler “opaque to optimization”, so that the first precondition must be checked on the supposition that the handler might not return (but rather throw or terminate).</p>
<p>The capability of establishing such a “checkpoint”, where subsequent program behavior, <em>even if undefined</em>, does not affect the preceding behavior, would be useful in general for purposes of stability and debugging.</p>
<p>There is already an analogous issue concerning program input: clearly a program can have undefined behavior for some inputs and not others. [intro.abstract]/3 and /5 acknowledge this by referring to “a given input” and “that input”, but such a monolithic approach neglects the paradoxical possibility of input correlated with, say, unspecified quantities:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="dt">int</span> x[<span class="dv">1</span>];</a>
<a class="sourceLine" id="cb3-2" data-line-number="2"></a>
<a class="sourceLine" id="cb3-3" data-line-number="3"><span class="dt">int</span> main() {</a>
<a class="sourceLine" id="cb3-4" data-line-number="4">  <span class="bu">std::</span>uintptr_t a=<span class="kw">reinterpret_cast</span>&lt;<span class="bu">std::</span>uintptr_t&gt;(x)%<span class="dv">3+1</span>,b;</a>
<a class="sourceLine" id="cb3-5" data-line-number="5">  <span class="bu">std::</span>cerr &lt;&lt; <span class="st">&quot;The car is behind door number &quot;</span> &lt;&lt; a</a>
<a class="sourceLine" id="cb3-6" data-line-number="6">              &lt;&lt; <span class="st">&quot;.  Door to open: &quot;</span>;</a>
<a class="sourceLine" id="cb3-7" data-line-number="7">  <span class="bu">std::</span>cin &gt;&gt; b;</a>
<a class="sourceLine" id="cb3-8" data-line-number="8">  <span class="cf">return</span> x[a-b];</a>
<a class="sourceLine" id="cb3-9" data-line-number="9">}</a></code></pre></div>
<p>This program might suggest 2 (if the cast yields, say, 0x1000), but one could absurdly argue that responding with 2 leads to undefined behavior because almost all of the unspecified possibilities for the “address” of <code>x</code> (<em>e.g.</em>, 0x2000) lead to undefined behavior for that input. An OOTA interpretation is also available: “<code>a</code> is really 3, so the input 2 leads to undefined behavior, whose effect is to print 2 instead of <code>a</code>”. We should reject this on the grounds of causality, since we require that undefined behavior respect input which can quite reasonably depend on <em>prior</em> output.</p>
<p>The standard does not have the necessary notion of <em>prior</em>, and this paper does not address this situation, but its checkpoints may be used to strengthen the guarantee of /7.3, that prompts are delivered before waiting for input, to include all observable behavior. This usage does exclude the OOTA interpretation: the output delivered to the host environment must accurately represent <code>a</code> if it is separated by a checkpoint from any potential undefined behavior.</p>
<h1 id="previous-work">Previous work</h1>
<p>I <a href="http://lists.isocpp.org/ext/2018/11/6427.php">suggested</a> a trick involving a <code>volatile</code> variable, based on the idea that a volatile read is <em>observable behavior</em> ([intro.abstract]/7) that must be preserved by optimization.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb4-1" data-line-number="1"><span class="kw">inline</span> <span class="dt">void</span> log(<span class="at">const</span> <span class="dt">char</span> *msg)</a>
<a class="sourceLine" id="cb4-2" data-line-number="2">{<span class="bu">std::</span>fputs(msg, stderr);}    <span class="co">// always returns</span></a>
<a class="sourceLine" id="cb4-3" data-line-number="3"></a>
<a class="sourceLine" id="cb4-4" data-line-number="4"><span class="dt">bool</span> on_fire() {</a>
<a class="sourceLine" id="cb4-5" data-line-number="5">  <span class="at">static</span> <span class="at">volatile</span> <span class="dt">bool</span> fire;  <span class="co">// always false</span></a>
<a class="sourceLine" id="cb4-6" data-line-number="6">  <span class="cf">return</span> fire;</a>
<a class="sourceLine" id="cb4-7" data-line-number="7">}</a>
<a class="sourceLine" id="cb4-8" data-line-number="8"></a>
<a class="sourceLine" id="cb4-9" data-line-number="9"><span class="dt">void</span> f(<span class="dt">int</span> *p) {</a>
<a class="sourceLine" id="cb4-10" data-line-number="10">  <span class="cf">if</span> (p == <span class="kw">nullptr</span>) log(<span class="st">&quot;bad thing 1&quot;</span>);</a>
<a class="sourceLine" id="cb4-11" data-line-number="11">  <span class="cf">if</span> (on_fire()) <span class="bu">std::</span>abort();</a>
<a class="sourceLine" id="cb4-12" data-line-number="12">  <span class="cf">if</span> (*p &gt;= <span class="dv">5</span>) log(<span class="st">&quot;bad thing 2&quot;</span>);</a>
<a class="sourceLine" id="cb4-13" data-line-number="13">}</a></code></pre></div>
<p>The idea is that the compiler cannot assume that <code>on_fire()</code> returns <code>false</code>, and so the check for <code>p</code> being null cannot be eliminated. However, the compiler can observe that, if <code>p</code> is null, the behavior will be undefined <em>unless</em> <code>on_fire()</code> returns <code>true</code>, and so it can elide that check (though not the volatile read) and call <code>abort()</code>. This therefore seems to convey a certain capability of <em>observing</em> the upcoming undefined behavior without actually experiencing it.</p>
<p>Unfortunately, conforming implementations are not constrained to follow this analysis. It is logically necessary that the implementation perform the observable volatile read unless it can somehow obtain its result otherwise. However, after reading the value <code>false</code> (as of course it will be in practice) the implementation may take any action whatsoever, even “undoing” the call to <code>log</code>. For example, it would be permissible to perform the implicit flush for <code>stderr</code> only just before the call to <code>std::abort</code> (which never happens). One might hope for the implementation to allow for the possibility that <code>log</code> affects some hardware state that affects the volatile read, but it might not as such a scheme would require support from the operating system.</p>
<h1 id="general-solution">General solution</h1>
<p>We can instead introduce a special library function</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb5-1" data-line-number="1"><span class="kw">namespace</span> std {</a>
<a class="sourceLine" id="cb5-2" data-line-number="2">  <span class="co">// in &lt;cstdlib&gt;</span></a>
<a class="sourceLine" id="cb5-3" data-line-number="3">  <span class="dt">void</span> observable() <span class="kw">noexcept</span>;</a>
<a class="sourceLine" id="cb5-4" data-line-number="4">}</a></code></pre></div>
<p>that divides the program’s execution into <em>epochs</em>, each of which has its own observable behavior. If any epoch completes without undefined behavior occurring, the implementation is required to exhibit the epoch’s observable behavior. Ending an epoch is nonetheless distinct from ending the program: for example, there is no automatic flushing of <code>&lt;cstdio&gt;</code> streams.</p>
<p>Undefined behavior in one epoch may obscure the observable behavior of a previous epoch (for example, by re-opening an output file), but external mechanisms such as pipes to a logging process can be used to guarantee receipt of an epoch’s output. With multiple threads, it is not the epochs themselves that are meaningful but their boundaries (or <em>checkpoints</em>); normal thread synchronization is required for the observable behavior of one thread to be included in an checkpoint defined by another.</p>
<p>As a practical matter, a compiler can implement <code>std::observable</code> efficiently as an intrinsic that counts as a possible termination, which the optimizer thus cannot remove. After optimization (including any link-time optimization), the code generator can then produce zero machine instructions for it. In Tokyo, some concerns were raised regarding implementability of this proposal, perhaps because of what then appeared to be dependence on the library function; the wording has been adjusted to avoid that implication. Discussions there and since with Michael Spencer suggest that the implementation strategy outlined in this paragraph is practicable.</p>
<p>Note that <code>std::observable</code> does not itself constitute observable behavior, and it does not forgive infinite non-trivial empty loops ([intro.progress]/1). There is no explicit connection to volatile access, but the ordinary happens-before rules apply (as much as possible given the vacuous [intro.abstract]/7.1). Finally, there is no guarantee that, for instance, local variables have been spilled to registers at each checkpoint: <code>std::observable</code> prevents certain program reorderings, but it is not a general aid for comprehensibility when using a debugger. (In general, it is difficult if not impossible to specify semantics that allow optimization and yet behave correctly when presented with input from a user equipped with a debugger.)</p>
<h2 id="limited-assumptions">Limited assumptions</h2>
A call to <code>std::observable</code> prevents the propagation of assumptions based on the potential for undefined behavior after it into code before it. The following functions offer the same opportunities for dead-code elimination:
<table>
<tr style="vertical-align: top">
<td>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb6-1" data-line-number="1"><span class="dt">void</span> a(<span class="dt">int</span> &amp;r, <span class="dt">int</span> *p) {</a>
<a class="sourceLine" id="cb6-2" data-line-number="2">  <span class="cf">if</span> (!p) <span class="bu">std::</span>fprintf(stderr, <span class="st">&quot;count: </span><span class="sc">%d\n</span><span class="st">&quot;</span>, ++r);</a>
<a class="sourceLine" id="cb6-3" data-line-number="3">  <span class="cf">if</span> (!p) <span class="bu">std::</span>abort();  <span class="co">// henceforth, p is known to be non-null</span></a>
<a class="sourceLine" id="cb6-4" data-line-number="4">  <span class="cf">if</span> (!p) <span class="bu">std::</span>fprintf(stderr, <span class="st">&quot;p is null</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb6-5" data-line-number="5">}</a></code></pre></div>
</td>
<td style="width: 5em">
</td>
<td>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb7-1" data-line-number="1"><span class="dt">void</span> b(<span class="dt">int</span> &amp;r, <span class="dt">int</span> *p) {</a>
<a class="sourceLine" id="cb7-2" data-line-number="2">  <span class="cf">if</span> (!p) <span class="bu">std::</span>fprintf(stderr, <span class="st">&quot;count: </span><span class="sc">%d\n</span><span class="st">&quot;</span>, ++r);</a>
<a class="sourceLine" id="cb7-3" data-line-number="3">  <span class="bu">std::</span>observable();</a>
<a class="sourceLine" id="cb7-4" data-line-number="4">  <span class="cf">if</span> (!p) <span class="bu">std::</span>fprintf(stderr, <span class="st">&quot;p is null</span><span class="sc">\n</span><span class="st">&quot;</span>);</a>
<a class="sourceLine" id="cb7-5" data-line-number="5">  *p += r;               <span class="co">// p may be assumed non-null</span></a>
<a class="sourceLine" id="cb7-6" data-line-number="6">}</a></code></pre></div>
</td>
</tr>
</table>
<p>In both cases, the “p is null” output can be elided: in <code>a</code>, because execution would not continue past the <code>std::abort</code>; in <code>b</code>, because of the following dereference of <code>p</code>. In both cases, the <code>count</code> output must appear if <code>p</code> is null: in <code>a</code>, because the program thereafter has the defined behavior of aborting; in <code>b</code>, because the epoch ends before undefined behavior occurs.</p>
<p>The function <code>b</code>, however, offers the additional optimization of not checking for null pointers at run time. It is very useful to support such optimizations without compromising diagnostics.</p>
<h2 id="usage">Usage</h2>
<p>The obvious place to use <code>std::observable</code> is after any sort of I/O that always returns, especially in any code run when an error is detected (and so imminent undefined behavior is likely). In a contracts context, the violation handler is one such routine; since <code>std::observable()</code> has no side effects, it would also be permissible to include it in specific contract conditions to guarantee that previous contracts are checked (even if the violation handler always returns):</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="dt">void</span> f(<span class="dt">int</span> *p) [[<span class="at">expects:</span> <span class="at">p</span>]] [[<span class="at">expects:</span> (<span class="at">std::observable</span>(), *<span class="at">p</span>&lt;<span class="at">5</span>)]];</a></code></pre></div>
<h2 id="implicit-approach">Implicit approach</h2>
<p>Martin Uecker proposed in <a href="https://open-std.org/JTC1/SC22/WG14/www/docs/n3128.pdf">WG14:N3128</a> that all I/O (including volatile accesses) might be implicitly considered an observable checkpoint (albeit without that phrasing, instead changing the definition of undefined behavior). (Formally this refers to <code>fflush</code> and not <code>printf</code>, but the latter calls the former on a schedule that the optimizer cannot in general predict.)</p>
<p>An objection might be raised to this approach that the compiler doesn’t know the semantics of every function that performs I/O (and we can’t expect, say, POSIX to annotate its definition of <code>write</code> with C++-specific text). However, such a situation is harmless: any function whose definition is truly unknown to the implementation might terminate the program, so no optimization can propagate back past a call to such a function anyway. If the compiler does know about a platform-specific I/O function (and, say, that it always returns), it is no more complicated for it to know that it is an optimization barrier as well.</p>
<p>The other plausible objection is that optimization might be too strongly affected by such ordering, although the I/O itself would tend to drown such savings. In August 2024, LEWG found these concerns not to be problematic and asked for library I/O to be an automatic checkpoint and asked for EWG to similarly consider the case of volatile accesses (where optimization might be more of a concern). If volatile accesses were also made observable, it would make sense to adopt the requisite changes to the definition of undefined behavior (and automatic checkpoints) without the user-accessible <code>std::observable</code>.</p>
<h1 id="wording">Wording</h1>
<p>Relative to N4988.</p>
<h2 id="intro.abstract">#[intro.abstract]</h2>
<p>Remove the note in paragraph 4:</p>
<blockquote>
<p>Certain other operations are described in this document as undefined behavior (for example, the effect of attempting to modify a const object).</p>
<p><s>[<em>Note</em>: This document imposes no requirements on the behavior of programs that contain undefined behavior. — <em>end note</em>]</s></p>
</blockquote>
<p>Insert before paragraph 5:</p>
<div class="ins">
<blockquote>
<p>Certain events in the execution of a program are termed <em>observable checkpoints</em>.</p>
<p>[<em>Note</em>: A call to <code>std::observable</code> ([support.start.term]) is an observable checkpoint. — <em>end note</em>]</p>
</blockquote>
</div>
<p>Change paragraph 5:</p>
<blockquote>
<p><u>The defined prefix of an execution comprises the operations <em>O</em> for which for every undefined operation <em>U</em> there is an observable checkpoint <em>C</em> such that <em>O</em> happens before <em>C</em> and <em>C</em> happens before <em>U</em>.</u></p>
<p><u>[<em>Note:</em> The undefined behavior that arises from a data race ([intro.races]) occurs on all participating threads. — <em>end note</em>]</u></p>
<p>A conforming implementation executing a well-formed program shall produce the <s>same </s>observable behavior <s>as</s><u>of the defined prefix of </u>one of the possible executions of the corresponding instance of the abstract machine with the same program and the same input. <s>However, i</s><u>I</u>f <s>any such</s><u>the selected</u> execution contains an undefined operation, <s>this document places no requirement on </s>the implementation executing that program with that input <s>(not even with regard to operations preceding the first undefined operation)</s><u>may produce arbitrary additional observable behavior afterwards</u>. If the execution contains an operation specified as having erroneous behavior, the implementation is permitted to issue a diagnostic and is permitted to terminate the execution at an unspecified time after that operation.</p>
</blockquote>
<p>Change paragraph 7:</p>
<blockquote>
<p>The <s>least requirements on a conforming implementation are:</s><u><em>observable behavior</em> of the program includes that</u></p>
<ol type="1">
<li>Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine.</li>
<li><p><s>At program termination, all d</s><u>D</u>ata <u>delivered to the host environment is</u> written into files<s> shall be identical to one of the possible results that execution of the program according to the abstract semantics would have produced</s><u> (C17 7.21.5.2)</u>.</p>
<u>[<em>Note:</em> Delivering such data is followed by an observable checkpoint ([cstdio.syn]). Not all host environments provide access to file contents before program termination. — <em>end note</em>]</u></li>
<li><p>The input and output dynamics of interactive devices shall take place in such a fashion that prompting output is actually delivered before a program waits for input. What constitutes an interactive device is implementation-defined.</p></li>
</ol>
<p><s>These collectively are referred to as the <em>observable behavior</em> of the program.</s></p>
<p>[<em>Note</em>: More stringent correspondences between abstract and actual semantics can be defined by each implementation. — <em>end note</em>]</p>
</blockquote>
<h2 id="support">#[support]</h2>
<h3 id="cstdlib.syn">#[cstdlib.syn]</h3>
<p>Add to the synopsis:</p>
<blockquote>
<p><code>[[noreturn]] void quick_exit(int status) noexcept;</code>    // <em>freestanding</em></p>
<p><u><code>void observable() noexcept;</code>    // <em>freestanding</em></u></p>
</blockquote>
<h2 id="support.start.term">#[support.start.term]</h2>
<p>Add at the end of the subclause:</p>
<div class="ins">
<blockquote>
<p><code>void observable() noexcept;</code></p>
</blockquote>
<blockquote>
<p><em>Effects:</em> Establishes an observable checkpoint ([intro.abstract]). No other effects.</p>
</blockquote>
</div>
<h2 id="cstdio.syn">#[cstdio.syn]</h2>
<p>Insert before paragraph 2:</p>
<div class="ins">
<blockquote>
<p>The return from each function call that delivers data to the host environment to be written to a file (C17 7.21.5.1, 7.21.5.2) is an observable checkpoint ([intro.abstract]).</p>
</blockquote>
</div>
</body>
</html>
