<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Correct and incorrect code, and &ldquo;erroneous behaviour&rdquo;</title>
    <style type="text/css">
      html { margin: 0; padding: 0; color: black; background-color: white; }
      body { margin: 0 auto; padding: 2em; font-size: medium; font-family: "DejaVu Serif", serif; line-height: 150%; max-width: 60em; }
      code { font-family: "DejaVu Sans Mono", monospace; color: #006; }

      h1, h2, h3 { margin: 1.5em 0 .75em 0; line-height: 125%; }
      h1 { clear: both; }

      div.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1em;
                 border-radius: 4px; }

      div.strictpre { white-space: pre; }

      sub, sup { margin: 0; padding: 0; line-height: 100%; }

      table { border-collapse: collapse; margin: 2em auto; }

      th, td { text-align: left; vertical-align: top; padding: .5ex 1em; margin: 0; }

      td.new { background-color: #EFE; }
      td.new:after { content: "new!"; font-family: "DejaVu Sans", sans-serif; font-weight: bold; font-size: xx-small;
                     vertical-align: top; top: -1em; right: -1em; position: relative; float: right; color: #090; }

      thead th { border-top: 2px solid #333; border-bottom: 2px solid #333; }
      tbody tr:last-child th, tbody tr:last-child td, tbody tr th.last { border-bottom: 2px solid #333; }
      tr.line td { border-bottom: 1px solid #333; }

      .docinfo { float: right }
      .docinfo p { margin: 0; text-align:right; }
      .docinfo address { font-style: normal; margin-bottom: 2em; }

      .quote { display: inline-block; clear: both; margin-left: 1ex;
                 border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1ex; }

      .modify { border-left: thick solid #999; border-right: thick solid #999; padding: 0 1em; }
      .insert { border-left: thick solid #0A0; border-right: thick solid #0A0; padding: 0 1em; }
      .insert h3, .insert h4, .insert p { text-decoration: underline; color: #0A0; }
      .comment { color: #456; }
      .inclassit { font-family: "DejaVu Serif", serif; font-style: italic; }
      .insinline { border-bottom: 2px solid #0A0; }

      ins { color: #090; }
      del { color: #A00; }
      ins code, del code, .insert code { color: inherit; }

      ul.wide li { margin-bottom: 1em; }
      ul.wide li div.code { padding: 0.25ex 1ex; margin: 1ex 0; }
    </style>
  </head>
  <body>
    <div class="docinfo">
      <p>ISO/IEC JTC1 SC22 WG21 P2795R0</p>
      <p>Date: 2023-02-10</p>
      <p>To: SG12, SG23, EWG, CWG</p>
      <address>
        Thomas K&ouml;ppe &lt;<a href="mailto:tkoeppe@google.com">tkoeppe@google.com</a>&gt;
      </address>
    </div>

    <h1>Correct and incorrect code, and &ldquo;erroneous behaviour&rdquo;</h1>

    <h2>Contents</h2>
    <!-- fgrep -e "<h2 id=" meaning_of_code.html | sed -e 's/.*id="\(.*\)">\(.*\)<\/h2>/<li><a href="#\1">\2<\/a><\/li>/g' -->
    <ol>
      <li><a href="#history">Revision history</a></li>
      <li><a href="#summary">Summary</a></li>
      <li><a href="#ttab">Example effects</a></li>
      <li><a href="#motivation">Motivation</a></li>
      <li><a href="#meaning">What is code?</a></li>
      <li><a href="#proposal">A proposal for C++</a></li>
      <li><a href="#examples">Concrete use case examples</a></li>
      <li><a href="#tooling">Tooling</a></li>
      <li><a href="#relwork">Related work</a></li>
      <li><a href="#implex">Implementation experience</a></li>
      <li><a href="#wording">Proposed wording</a></li>
      <li><a href="#qna">Questions and answers</a></li>
      <li><a href="#references">References</a></li>
    </ol>

    <h2 id="history">Revision history</h2>
    <ul>
      <li>P2795R0: This initial revision.</li>
    </ul>

    <h2 id="summary">Summary</h2>

    <p>
      We propose a novel kind of behaviour for C++ which allows us to formally speak about
      &ldquo;buggy&rdquo; (or &ldquo;incorrect&rdquo;) code, that is, code that does not mean
      what it should mean (in a sense we will discuss). The current C++ Standard only speaks
      about well-defined and well-behaved programs, and imposes no requirements on any other
      program. This results in an overly simple dichotomy of a program either being correct as
      written, with specified behaviour, or being incorrect and entirely outside the scope of
      the Standard. It is not possible for program to be incorrect, yet have its behaviour
      constrained by the Standard.
    </p>
    <p>
      The newly proposed <em>erroneous behaviour</em> fills this gap. It is well-defined
      behaviour that is nonetheless acknowledged as being &ldquo;incorrect&rdquo;, and thus
      allows implementations to offer helpful diagnostics, while at the same time being
      constrained by the specification.
    </p>
    <p>
      Adopting erroneous behaviour for a particular operation consists of replacing current
      undefined behaviour with a (well-defined) specification of that operation&rsquo;s
      behaviour, explicitly called out as &ldquo;erroneous&rdquo;. This will in general have a
      performance cost. <em>This paper does not propose any particular adoption of erroneous
      behaviour</em> (but we give examples of <em>possible</em> adoptions below). Instead, we expect
      each such adoption to be its own extension proposal.
    </p>
    <p>
      The impact of changing an operation&rsquo;s current undefined behaviour to erroneous
      behaviour is as follows:
    </p>
    <ul>
      <li>On correct code: none observable, but possible performance cost.</li>
      <li>On incorrect code: if the code leads to previously undefined behaviour that
        is changed to erroneous behaviour, the code is still incorrect, but the behaviour
        is now as specified in the chnage, not unconstrained.</li>
    </ul>

    <h2 id="ttab">Example effects</h2>

    <p>
      In this example we assume a hypothetical change in which the value of a
      default-initialized variable with automatic storage duration is erroneously well-defined.
      (This is a motivating use case for this proposal, but it is a strictly separate decision
      whether and how we would want to make such a change.)
    </p>

    <table>
      <col width="50%">
      <col width="50%">
      <thead>
        <tr><th>C++20</th><th>This proposal, applied hypothetically to automatic variable initialization</th></tr>
      </thead>
      <tbody>
        <tr class="line">
          <td colspan="2" style="text-align: center; padding: 1ex;"><div style="text-align: left; display: inline-block;"><code>extern void f(int);<br>int x;<br>f(x);</code></div></td>
        </tr>
        <tr>
          <td>undefined behaviour</td>
          <td>erroneous behaviour</td>
        </tr>
        <tr>
          <td>definitely a bug</td>
          <td>definitely a bug</td>
        </tr>
        <tr>
          <td>required to be accepted</td>
          <td>may be accepted or rejected</td>
        </tr>
        <tr>
          <td>common compilers allow rejecting (e.g. <code>-Werror</code>), this is non-conforming</td>
          <td>conforming compilers are allowed to reject</td>
        </tr>
      </tbody>
    </table>

    <h2 id="motivation">Motivation</h2>

    <p>
      The pragmatic reality of real-world is that there are very few C++ programs that are
      entirely correct. In terms of the Standard, that means most programs are not constrained
      by the specification at all, since they run in to undefined behaviour. This is ultimately
      not very helpful to real software development efforts.
    </p>
    <p>
      What we cannot currently do within the Standard is to talk about the behaviour of such
      incorrect programs. However, there has long been an active discussion around precisely
      this kind of behaviour: the term &ldquo;safety&rdquo; has been mentioned as a concern in
      both C and C++, but it is a nebulous and slippery term that means different things to
      different people. (Dave Abrahams and Sean Parent give a useful definition,
      see <a href="#relwork">below</a>.) What makes this term hard to pin down is that we do
      not have an agreed upon language to define it: safety concerns the behaviour
      of <em>incorrect</em> programs, but incorrect programs currently aren't C++ at all! In
      other words, all C++ programs are safe, but most programs aren't C++ programs. Again, this
      is not helpful.
    </p>
    <p>
      A simple and frequently heard suggestion is to make more code correct by changing what is
      currently undefined behaviour into well-defined behaviour. We would like to discuss this
      approach in detail.
    </p>


    <h2 id="meaning">What is code?</h2>

    <p><em>I would like to discuss this position, and I hope to build consensus around it.</em></p>

    <p>
      Code is communication. Primarily, code communicates an idea <em>among humans</em>. Humans
      work with code as an evolving and accumulating resource. Its role in software engineering
      projects is not too different from the role of traditional literature in the pursuit of
      science, technology, and engineering: literature is how individuals learn from and
      contribute to collective progress. The fact that code can also be interpreted and executed
      by computers is of course also important, but secondary. (There are many ways one can
      instruct a machine, but not all of them are suitable for building a long-term ecosystem.)
    </p>
    <p>
      The language of code are programming languages, and the medium is source code, just like
      natural languages written in books, emails, or spoken in videos are the media of
      traditional literature. Like all media, source code is imperfect and ambiguous. The
      purpose of a text is to communicate an idea, but the entire communication has to be
      funnelled through the medium, and understood by the audience. Without the author present to
      explain what they really meant, the text is the only clue to the original idea; any act of
      reading a text is always an act of forensic reconstruction of the original idea. If the
      text is written well and &ldquo;clear&rdquo;, then readers can perform this reconstruction
      with high confidence that they &ldquo;got it right&rdquo; and feel themselves
      understanding the idea; they are &ldquo;on the same page&rdquo; as the author. On the
      other hand, poor writing leads to ambiguous text, and reading requires interpretation and
      often guess-work. This is no different in natural languages than in computer code.
    </p>
    <p>
      I would like to propose that we appreciate the value of code <em>as communication with
      humans</em>, and consider how well a programming language works for that purpose in medium
      of source code.  Source code is often shared among a large group of users, who are
      actively working with the code: code is only very rarely a complete black-box that can be
      added to a project without further thought. At the very least, interfaces and vocabulary
      have to be understood. But commonly, too, code has to be modified in order to be
      integrated into a project, and to be evolved in response to new requirements. Last but not
      least, code often contains errors, which have to be found, understood, and fixed. All of
      the above efforts may be performed by a diverse group of users, none of whom need to have
      intimate familiarity with any one piece of code. There is value in having <em>any</em>
      competent users be able to read and understand any one piece of code &mdash; not
      necessarily in all its domain depth, but well enough to work with it in the context of a
      larger project. To extent the analogy with natural language above, this is similar to how
      a competent speaker of a language should be able to understand and integrate a well-made
      argument in a discussion, even if they are not themselves an expert in the domain of the
      argument.
    </p>
    <p>
      How does all this connect to C++? Like with code in any programming language, given a
      piece of code, a user should be able to understand the idea that the code is
      communicating. Absent a separate document that says &ldquo;Here is what this code is meant
      to do:&rdquo;, the main source of information available to the user is the behaviour of
      the code itself. Note how this has nothing to do with compiling and running code. At this
      point, the code and the idea it communicates exist only in the minds of the author and the
      reader; no compilation is involved. How well the user understands the code depends on how
      ambiguous the code is, that is, how many different things it can mean. The user interprets
      the code by choosing a possible meaning to it from among the choices, where we assume that
      the code is <em>correct</em>: in C++, that means correct in the sense of the Standard,
      being both well-formed and executing with well-defined behaviour. This is critical: the
      constraint of presumed correctness serves as a dramatic aid for interpretation. If we
      assume that code is correct, then we can dismiss any interpretation that would require
      incorrect behaviour, and we only have to decide among the few remaining valid
      interpretations. The more valid interpretations a construction has, the more ambiguity a
      user has during interpretation of the entire piece of code. C++ defines only a very narrow
      set of behaviours, and everything else is left as the infamous <em>undefined
      behaviour</em>, which we could say is not C++ at all, in the sense that we assume that
      that's not what could possibly have been meant. Practically, of course, we would not
      dismiss undefined behaviour as &ldquo;not C++&rdquo;, but instead we would treat it as a
      definitive signal that the code is not communicating its idea correctly. (We could then
      either ask the author for clarification, or, if we are confident to have understood the
      correct idea anyway, we can fix the code to behave correctly. I claim that in this
      long-term perspective on code as a cultural good, buggy code with a clear intention is
      better than well-behaved, ambiguous code: if the intention is clear, then I can see if the
      code is doing the right thing and fix it if not, but without knowing the intention, I have
      no idea if the well-behaved code is doing what it is supposed to.)
    </p>


    <h2 id="proposal">A proposal for C++</h2>

    <p>
      We can finally state a current problem in C++ and propose a solution. Current C++ has no
      formal concept of incorrect code beyond undefined behaviour (which includes any execution
      of an ill-formed program). This would be sufficient in a world where C++ programs were
      generally correct, but in practice, the complexity both inherent to the language and
      inevitable in projects of any significant size means that real C++ programs are almost
      never free from errors. The tension arises because such programs are deployed in the real
      world, but their behaviour is entirely unconstrained by the C++ standard, and in practice
      there have been a significant number of of dangerous or outright harmful
      behaviours. [References to CVEs etc.] From the point of view of actual <em>behaviour</em>,
      as opposed to the intended <em>meaning</em> of code discussed in the previous section, this
      situation is problematic, since the very real danger and harm are immediate problems.
    </p>
    <p>
      Our proposed solution is to address both actual behaviour and the meaning of &ldquo;code
      as a medium&rdquo; by formally acknowledging incorrect behaviour, and allowing the
      language specification to take it into account:
    </p>
    <ul>
      <li>
        We want the actual behaviour of code to fall under the scope of the Standard
        (different from today).
      </li>
      <li>
        We want the retain the power of code to communicate ideas, which concretely means that
        we do not want to make previously undefined behaviour assume meaning. (We can make it
        well-defined, but we want to preserve the fact that it can never have been intentional
        on part of the author.)
      </li>
    </ul>
    <p>
      The proposal is to add a novel kind of behaviour to C++, which we tentatively call
      <em>erroneous behaviour</em>:
    </p>
    <p style="margin: 0 2em;"><strong>erroneous behaviour:</strong> well-defined behaviour
      (which includes implementation-defined and unspecified behaviour) which allows the
      implementation to issue a diagnostic message
    </p>
    <p>
      Erroneous behaviour is never intended. Its presence is therefore a definitive sign that
      the code is not communicating correctly and needs to be fixed. At the same time,
      erroneous behaviour is indeed defined. Implementations must exhibit the defined
      behaviour, at least up until a diagnostic is issued (if ever). There is no risk of damage
      or harm from executing erroneous behaviour.
    </p>
    <p>
      Erroneous behaviour can be used to improve safety if we use it to undefined behaviour
      from constructs that are currently frequently found in incorrect code. This would change
      such code to be correct, though unintended/erroneous. Its behaviour would no longer be
      unconstrained, but instead be specified by the Standard. At the same time, readers can now
      assume that C++ code is both correct <ins>and not erroneous</ins>, and thus continue to
      be able to interpret code in the same way as they do today, without having to assume that
      code could suddenly acquire new meaning.
    </p>
    <p>
      Note that the diagnostic is not immediately tied to the erroneous behaviour but could be
      issued at any later point. Implementations that want to diagnose would not be required to
      track every behaviour immediately, but could, for example, aggregate findings and only
      diagnose some sparse checkpoints.
    </p>
    <p>
      Once the notion of erroneous behaviour exists in the Standard, we can entertain proposals
      to replace current undefined behaviour with erroneous behaviour. This generally comes at a
      performance cost, and should be a case-by-case analysis. The difference between undefined
      and erroneous behaviours is that the latter constrains implementations, and we need to
      consider whether that is a worthwhile trade-off, considering the likelihood of user
      mistakes and the the potential danger of undefined behaviour.  We will give example
      applications in the next section, but they do not form part of this proposal.
    </p>


    <h2 id="examples">Concrete use case examples</h2>

    <h3 id="exover">Overview</h3>

    <p>
      This section shows a few possible applications of erroneous behaviour. That is,
      each example describes an operation that currently has undefined behaviour, and
      suggests how one might define the behaviour, and make it erroneous.
    </p>

    <h3 id="exauto">Initialization automatic variables</h3>
    <p>
      [to be fleshed out] Proposal: make it so that <code>int x;</code> gives <code>x</code>
      an implementation-defined object representation and an indeterminate value representation,
      and if glvalue-to-prvalue conversion is applied to such a glvalue of indeterminate value,
      the result is the value implied by that object representation, and the behaviour is erroneous.
    </p>
    <p>
      Note that we do not actually make the value 0, but leave it up to the implementation. The
      assumption is that production implementations will use 0 and never diagnose the erroneous
      behaviour, whereas debug builds might put some other pattern into the initial value, a
      hardened build might select a runtime-randomized value (to detect unwarranted reliance on
      the value), and runtime sanitizers can track access to the uninitialized value and
      diagnose it. This is ultimately a detail, but we consider this choice superior to
      guaranteeing the value zero.
    </p>

    <h3 id="expun">Type punning</h3>
    <p>
      Proposal: make type-punned access erroneous, so as to address this related
      vulnerability:
    </p>
    <div class="code">float x;
      print_secret(reinterpret_cast&lt;int&amp;&gt;(x));
    </div>
    <p>
      This might be achieved by erroneously giving the access the value that is assumed by
      the object representation, or some other value, or erroneously terminate.
    </p>
    <p>
      Note that the proposal from P2723R1 to make automatic-storage variables initialized to
      zero does not actually help in this example, since the compiler can still see the
      undefined behaviour from the type-punned access and thus is permitted to perform the
      initialization.
    </p>

    <h3 id="exflow">Signed integer overflow</h3>
    <p>
      Proposal: make the value of signed integer overflow to erroneously be the
      twos&rsquo;-complement value.
    </p>
    <p>
      This proposal is perhaps special in that it does not need to incur a direct implementation
      cost on platforms that already perform this operation in hardware. (However, the cost of the
      missed optimisation based on reaching undefined behaviour remains.)
    </p>

    <h3 id="exptrarr">Pointer arithmetic, array access</h3>
    <p>
      Proposal: dereferencing a null pointer could result, erroneously, in some fixed value, or
      terminate erroneously. Similarly for accessing an array of known bound out of bounds.
    </p>
    <p>
      This clearly has a runtime cost. For arrays this would be mandatory bounds checking for
      all arrays of known bound.
    </p>

    <h3 id="exstderr">User-defined erroneous behaviour</h3>
    <p>Proposal: define a magic library function:</p>
    <div class="insert">
      <div class="code">std::erroneous_behaviour();</div>
      <p><em>Effects</em>: Does nothing, erroneously.</p>
    </div>

    <p>
      Thus function can allows library code to define its own erroneous behaviour, and reaching
      this function could be detectable by tooling.
    </p>

    <h3 id="exstdlib">Preconditions in the standard library</h3>
    <p>
      The standard library currently imposes <em>Preconditions:</em> on functions,
      and violation of those preconditions is defined to result in undefined behaviour.
      This is sometimes called "soft" or "library" undefined behaviour, since it is not
      actually detectable in the core language, but in general only by a human reader.
    </p>
    <p>
      We could add a variation of preconditions that lead to erroneous behaviour. For those, we
      would have to specify the outcome, but reaching such behaviour could be detectable by
      tooling.
    </p>

    <h3 id="exuserlib">API design choices</h3>
    <p>
      This is an example of the various options for putting contracts (both explicit and
      implicit) on a function API. Consider a hypothetical array with some knowable bound,
      and an accessor function that we will discuss:
    </p>
    <div class="code"><!--
-->   extern int data[]; &nbsp; // size given by data_len
      extern int data_len;

      int get_data(std::size_t i);
    </div>
    <ul class="wide">
      <li>
        <strong>Narrow contract, with UB:</strong>
        &ldquo;Returns <code>data[i]</code>, requires <code>0 &lt;= i &amp;&amp; i &lt; 0</code>.&rdquo;
        Implementation:<div class="code">return data[i];</div>
        This is &ldquo;unsafe&rdquo; in the sense of Abrahams and Parent.
      </li>
      <li>
        <strong>Narrow contract, preconditions asserted:</strong>
        &ldquo;Returns <code>data[i]</code>, requires <code>0 &lt;= i &amp;&amp; i &lt; data_len</code>.&rdquo;
        Implementation:<div class="code" style="margin-top: 1ex;">if (0 &lt;= i &amp;&amp; i &lt; data_len) return data[i];
          std::abort();</div>
        This is &ldquo;strongly safe&rdquo; in the sense of Abrahams and Parent.
        Human readers can see that violating preconditions is an error, but it is hard for tooling to see this.
      </li>
      <li>
        <strong>Narrow contract, erroneous result:</strong>
        &ldquo;Returns <code>data[i]</code> if <code>0 &lt;= i &amp;&amp; i &lt; data_len</code>, otherwise erroeneously returns <code>-8</code>.&rdquo;
        Implementation:<div class="code" style="margin-top: 1ex;">if (0 &lt;= i &amp;&amp; i &lt; data_len) return data[i];
          std::erroneous_behaviour();
          return -8;</div>
        This has no undefined behaviour, but detectable erroneous behaviour.
      </li>
      <li>
        <strong>Wide contract, preconditions asserted:</strong>
        &ldquo;Returns <code>data[i]</code> if <code>0 &lt;= i &amp;&amp; i &lt; data_len</code>, otherwise terminates.&rdquo;
        Implementation:<div class="code" style="margin-top: 1ex;">if (0 &lt;= i &amp;&amp; i &lt; data_len) return data[i];
          std::abort();</div>
        Similar to &ldquo;narrow contract, preconditions asserted&rdquo;, but here termination
        is part of the API. E.g. users could call this function for the deliberate purpose of
        terminating, and that would not be a programming error.
      </li>
      <li>
        <strong>Wide contract:</strong>
        &ldquo;Returns <code>data[i]</code> if <code>0 &lt;= i &amp;&amp; i &lt; data_len</code>, otherwise returns <code>-8</code>.&rdquo;
        Implementation:<div class="code" style="margin-top: 1ex;">if (0 &lt;= i &amp;&amp; i &lt; data_len) return data[i];
          return -8;</div>
      </li>
    </ul>

    <h2 id="tooling">Tooling</h2>

    <p>
      While we have been emphasising the importance of code readability and understandability,
      we must also consider the practicalities of actually compiling and running code. Whether
      code has meaning, and if so, which, impacts tools. There are two important, and sometimes
      opposed, use cases we would like to consider.
    </p>

    <h3>Production compilers</h3>

    <p>
      Getting code to run in production often comes with two important (and also opposed)
      expectations:
    </p>
    <ul>
      <li>Performance: code should use as few resources as possible to achieve its specified behaviour.</li>
      <li>Safety: incorrect code should not have harmful side effects.</li>
    </ul>
    <p>
      Undefined behaviour, and in particular its implications on the meaning of code, is
      increasingly exploited by compilers to optimize code generation. By assuming that
      undefined behaviour can never have been intentional, transitive assumptions can be derived
      that allow for far-reaching optimizations. This is often desirable and beneficial for
      correct code (and demonstrates the value of unambiguously understandable code: even
      compilers can use this reasoning to determine how much work does and does not have to be
      done). However, for incorrect code this can expose vulnerabilities, and thus constitute a
      considerable lack of safety.
      <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1093r0.pdf">P1093R0</a>
      discusses these performance implications of undefined behaviour.
    </p>
    <p>
      The proposed erroneous behaviour retains the same meaning of code as undefined behaviour
      for human readers, but the compiler has to accept that erroneous behaviour can happen.
      This constrains the compiler (as it as to ensure erroneous results are produced correctly),
      but in the event of incorrect code (which all erroneous behaviour requires), the resulting
      behaviour is constrained by the Standard and does not create a safety hazard. In other words,
      erroneous behaviour has a potential performance cost compared to undefined behaviour, but
      is safer in the presence of incorrect code.
    </p>

    <h3>Debug toolchains and sanitizers</h3>

    <p>
      The other major set of tools that software projects use are debugging tools. Those include
      extra warnings on compilers, static analysers, and runtime sanitizers. The former two are
      good at catching some localised bugs early, but do not catch every bug. Indeed one of the
      main limitations we seem to be discovering is that there is reasonable C++ code for which
      important analyses cannot be performed statically. (Note that
      <a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2687r0.pdf">P2687R0</a>
      proposes a safety strategy in which static analysis plays a major role.) Runtime
      sanitizers like ASAN, MSAN, TSAN, UBSAN, on the other hand, have excellent abilities to
      detect undefined behaviour at runtime with virtually no false positives, but at a
      significant build and runtime cost.
    </p>
    <p>
      Both runtime sanitizers and static analysis can use the code readability signal from both
      undefined and erroneous behaviour equally well. In both cases it is clear that the code is
      incorrect. For undefined behaviour, implementations are unconstrained anyway and tools may
      reject or diagnose at runtime. The goal of erroneous behaviour is to permit the exact same
      treatment, by allowing a conforming implementation to diagnose, terminate (and also reject)
      a program that contains erroneous behaviour.
    </p>

    <p>
      In other words, erroneous behaviour retains the understandability and debuggability of
      undefined behaviour, but also constrains the implementation just like well-defined
      behaviour.
    </p>

    <h3>Usage profiles</h3>

    <p>The following toolchain deployment examples are based on real-world setups.</p>
    <ul>
      <li>
        A safety-critical production system (e.g. one that handles user data) compiles code
        treating erroneous behaviour as well-defined, not issuing diagnostics. Compared to the
        status quo, the resulting executable is safer since erroneous behaviour is well-defined.
      </li>
      <li>
        A safety-noncritical, high-performance system (e.g. a scientific simulation) may use a
        toolchain that assumes that no erroneous behaviour exists (similar
        to <code>-ffast-math</code>, which assumes that all floating point values lie in a
        certain range). This allows for best-possible performance, and corresponds to the status
        quo. Debugging and testing are performed separately.
      </li>
      <li>
        Debugging and testing deployments, including unit tests, use runtime sanitizers to
        detect undefined and erroneous behaviour. This is a continuous part of a larger
        production ecosystem, where test coverage and fuzzing tools try to expose as much of the
        production code to sanitizers as possible, and it is cultivated as part of the overall
        production effort.
      </li>
    </ul>


    <h2 id="relwork">Related work</h2>

    <p>
      Sean Parent&rsquo;s presentation
      <em><a href="https://sean-parent.stlab.cc/presentations/2021-11-14-domain-of-operation/2021-11-14-domain-of-operation.pdf">Reasoning
      About Software Correctness</a></em> (and also subsequent Cpp North 2022 keynote talk)
      give a useful definition of &ldquo;safety&rdquo; adapted specifically to C++ and
      which explicitly only concerns <em>incorrect code</em>. He defines a function to be safe
      if it does not lead to undefined behaviour (that is, even when preconditions are violated).
      He points out that safety composes, whereas
      correctness does not (i.e. a composition of safe calls is itself safe, whereas a composition
      of correct calls is not intrinsically correct, but only if preconditions hold). He argues,
      similarly to our argument in this proposal, that it would not be helpful to turn undefined
      behaviour into well-defined behaviour for the purpose of making functions safe, since that
      would merely hide bugs; instead, a helpful change would be for unsafe operation to become
      &ldquo;strongly safe&rdquo;, which for him means that it terminates on precondition violation.
      If the current proposal were to adopt these terms, we would instead merely require that strong
      safety would lead to erroneous behaviour (rather than outright termination), and leave the
      actual behaviour implementation-defined.
    </p>

    <p>
      JF Bastien's paper P2723R1 proposes addressing the safety concerns around automatic variable
      initialization by just defining variables to be initialized to zero. The previous revision of
      that paper was what motivated the current proposal: The resulting behaviour is desirable,
      but the cost on code understandability is unacceptable to the present author.
    </p>

    <p>
      The papers P2687R0 by Bjarne Stroustrup and Gabriel Dos Reis and P2410R0 by Bjarne
      take a more general look at how to arrive at a safe language. They
      recommends a combination of static analysis and restrictions on the use of the language so
      as to make static analysis very effective. However, on the subject of automatic variable
      initialization specifically they offers no new solution: P2687R0 only recommends either
      zero-initialization or annotated non-initialization (reading of which results in UB); in
      that regard it is similar to JF Bastien's proposal. P2410R0 states that &ldquo;[s]tatic
      analysis easily prevents the creation of uninitialized objects&rdquo;, but the intended result
      of this prevention, and in particular the impact on code understandability, is left open.
    </p>

    <p>
      Tom Honerman proposed a system of &ldquo;diagnosable events&rdquo;, which is largely
      aligned with the values and goals of this proposal, and takes a quite similar approach:
      Diagnosable events have well-defined behaviour, but implementations are permitted to
      handle them in an implementation-defined way.
    </p>

    <p>
      Davis Herring's paper P1492R2 proposes a checkpointing system that would stop undefined
      behaviour from having arbitrarily far-reaching effects. That is a somewhat different
      problem area from the present safety one, and in particular, it does not control the
      effects of the undefined behaviour itself, but merely prevents it from interfering with
      other, previous behaviour. (E.g. this would not prevent the leaking of secrets via
      uninitialized variables.)
    </p>

    <p>
      The Ada programming language has a notion of bounded undefined behaviour.
    </p>

    <p>
      Paper P1093R0 by Bennieston, Coe, Gahir and Russel discusses the value of undefined
      behaviour in <em>correct</em> code and argues for
      the value of the compiler optimizations that undefined behaviour permits. This is
      essentially the tool&rsquo;s perspective of the value of undefined behaviour for the
      interpretability of code which we discussed above: both humans and compilers benefit from
      being able to understand code with fewer ambiguities. Compilers can use the absence of
      ambiguities to avoid generating unnecessary code. The paper argues that we should not
      break these optimizations lightheartedly by making erstwhile undefined behaviour well-defined.
    </p>


    <h2 id="implex">Implementation experience</h2>

    <p>
      Applying erroneous behaviour to the default initialization of automatic variables is
      already available today. Clang and GCC expose an example of the new production behaviour
      when given the flag <code>-ftrivial-auto-var-init=zero</code>. Clang exposes the
      error-detecting behaviour when using its Memory Sanitizer (which currently detects
      undefined behaviour, and would have to be taught to also recognize erroneous behaviour).
    </p>
    <p>
      The proposal primarily constitutes a change of the specification tools that we have
      available in the Standard, so that we have a formal concept of incorrect code that the
      Standard itself can talk about. It should only pose a minor implementation burden.
    </p>


    <h2 id="wording">Proposed wording</h2>

    <p>Add an entry to [3, intro.defs]:</p>
    <div class="insert">
      <p><ins>3.? erroneous behaviour [defns.erroneous]</ins></p>
      <p><ins>well-defined behavior (including implementation-defined and unspecified behavior)
          which is subject to additional conformance constraints</ins></p>
      <p><ins>[<em>Note 1 to entry</em>: Erroneous behaviour is always the consequence of
      incorrect program code. Implementations are allowed, but not required to diagnose it
      ([4.1.1, intro.compliance.general]). &mdash;&nbsp;<em>end note</em>]</ins></p>
    </div>

    <p>Modify and add a list item to [4.1.1, intro.compliance.general] paragraph 2:</p>
    <div class="modify">
      <ul>
        <li>If a program contains no violations of the rules in
          [Clause 5, lex] through [Clause 33] and [Annex D, depr],
          a conforming implementation shall,
          within its resource limits as described in [Annex B, implimits],
          accept and <del>correctly </del>execute[footnote] that program<ins> as defined</ins>.</li>
        <li><ins>If a program is as in the previous sentence except that it also contains an occurrence
          of a construct described in this document as having &ldquo;erroneous behaviour&rdquo;,
          a conforming implementation shall also accept and execute that program as above,
          except that it is allowed to issue a diagnostic when or after the erroneous behavior
          is executed, and after such a diagnostic the behaviour is implementation-defined.
          Additionally, the implementation is not required to accept a translation unit ([lex.separate, 5.1])
          if it can determine that erroneous behaviour is reachable within that translation unit.
          [<em>Note</em>: It is intended that an implementation either execute erroneous behavior
          without diagnostic, or issue a diagnostic and continue, or issue a diagnostic and terminate.&nbsp;&mdash;<em>end note</em>]
        </ins></li>
	<li>If a program contains a violation of any diagnosable rule or an occurrence of a
          construct described in this document as &ldquo;conditionally-supported&rdquo; when the
          implementation does not support that construct, a conforming implementation shall
          issue at least one diagnostic message.</li>
        <li>&hellip;</li>
      </ul>
    </div>


    <h2 id="qna">Questions and answers</h2>

    <p>
      <strong>Do you really mean that there can never be any UB in any correct code?</strong>
      There is of course always room for nuance and detail. If a particular construction is
      known to be UB, but still appropriate on some platform or under some additional
      assumptions, it is perfectly fine to use it. It should be documented/annotated
      sufficiently, and perhaps tools that detect UB need to be informed that the construction
      is intentional.
    </p>

    <p>
      <strong>Why is static analysis not enough to solve the safety problem of UB? Why do we need sanitizers?</strong>
      Current C++ is not constrained enough to allow static analysis to accurately detect all
      cases of undefined behaviour. (For example, C++ allows initializing a variable via a call
      to a function in a separate translation unit or library.) Other languages like Rust manage
      to prevent unsafe behaviour statically, but they are more constrained (e.g. Rust does not
      allow passing an uninitialized value to a function). Better static analysis is frequently
      suggested as a way to address safety concerns in C++ (e.g. P2410R0, P2687R0), but this
      usually requires adopting a limited subset of C++ that is amenable to reliable static
      analysis. This does not help with the wealth of existing C++ code, neither with making it
      safe nor with making it correct. By contrast, runtime sanitizers can reliably point out
      when undefined behaviour is reached.
    </p>

    <p>
      <strong>Why is <code>int x;</code> any different from <code>std::vector&lt;int&gt;
      v;</code>?</strong>  Several reasons. One is that <code>vector</code> is a class with
      internal invariants that needs to be destructible, so a well-defined initial state already
      suggests itself. The other is that a vector is a container of elements, and if the
      initializer does not provide any elements, then a vector with no elements is an
      unsurprising result. By contrast, if there is no initial value given for
      an <code>int</code>, there is no single number that is better or more obviously right than
      any other number. Zero is a common choice in other languages, but it does not seem helpful
      in the sense of making it easy to write unambiguous code if we allow a novel spelling of
      a zero-valued <code>int</code>. If you mean zero, just say <code>int x = 0;</code>.
    </p>

    <p>
      <strong>Is this proposal better than defining <code>int x;</code> to be zero?</strong>
      It depends on whether you want code to deliberately use <code>int x;</code> to mean,
      deliberately, that <code>x</code> is zero. The counter-position, shared by this author, is
      that zero should have no such special treatment, and all initialization should be
      explicit, <code>int x = -1, y = 0, z = +1;</code>. All numeric constants are worth seeing
      explicitly in code, and there is no reason to allow <code>int x;</code> as a valid
      alternative for one particular case that already has a perfectly readable spelling.
      (An explicit marker for a deliberately uninitialized variable is still a good idea,
      and accessing such a variable would remain undefined behaviour, and not become
      erroneous even in this present proposal.)
    </p>


    <h2 id="references">References</h2>
    <ul>
      <li>
        Andrew Bennieston, Jonathan Coe, Daven Gahir, Thomas Russel,
        <em><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1093r0.pdf">P1093R0</a>: Is undefined behaviour preserved?</em>
      </li>
      <li>
        Tom Honerman,
        <em>Posioned values: A feature and specification mechanism to aid diagnosis of implicitly initialized variables</em>, private communication.
      </li>
      <li>
        Davis Herring,
        <em><a href="https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2021/p1494r2.html">P1494R2</a>: Partial program correctness</em>.
      </li>
      <li>
        JF Bastien,
        <em><a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2723r1.html">P2723R1</a>: Zero-initialize objects of automatic storage duration</em>.
      </li>
      <li>
        Dave Abrahams,
        private communication.
      </li>
      <li>
        Sean Parent,
        <em><a href="https://sean-parent.stlab.cc/presentations/2021-11-14-domain-of-operation/2021-11-14-domain-of-operation.pdf">Reasoning About Software Correctness</a></em>.
      </li>
      <li>
        Sean Parent,
        Cpp North 2022 keynote talk, <em><a href="https://www.youtube.com/watch?v=kZCPURMH744">The Tragedy of C++</a></em>.
      </li>
      <li>
        Bjarne Stroustrup, Gabriel Dos Reis,
        <em><a href="https://open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2687r0.pdf">P2687R0</a>: Design Alternatives for Type-and-Resource Safe C++</em>.
      </li>
      <li>
        Bjarne Stroustrup,
        <em><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2410r0.pdf">P2410R0</a>: Type-and-resource safety in modern C++</em>.
      </li>
    </ul>

  </body>
</html>
