narrow_contract.html 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  2. <html><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  3. <title>Narrow contracts - Boost.Outcome documentation</title>
  4. <link rel="stylesheet" href="../css/boost.css" type="text/css">
  5. <meta name="generator" content="Hugo 0.52 with Boostdoc theme">
  6. <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
  7. <link rel="icon" href="../images/favicon.ico" type="image/ico"/>
  8. <body><div class="spirit-nav">
  9. <a accesskey="p" href="../motivation/plug_error_code2.html"><img src="../images/prev.png" alt="Prev"></a>
  10. <a accesskey="u" href="../motivation.html"><img src="../images/up.png" alt="Up"></a>
  11. <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../tutorial.html"><img src="../images/next.png" alt="Next"></a></div><div id="content">
  12. <div class="titlepage"><div><div><h1 style="clear: both">Narrow contracts</h1></div></div></div>
  13. <p>A program&rsquo;s thread of execution can enter a &ldquo;disappointing&rdquo; state for two reasons:</p>
  14. <ul>
  15. <li>due to disappointing situation in the environment (operating system, external input),
  16. or</li>
  17. <li>due to a bug in the program.</li>
  18. </ul>
  19. <p>The key to handling these disappointments correctly is to identify to which
  20. category they belong, and use the tools adequate for a given category. In this
  21. tutorial when we say &ldquo;error&rdquo; or &ldquo;failure&rdquo; we only refer to the first category.
  22. A bug is not an error.</p>
  23. <p>A bug is when a program is something else than what it is supposed to be. The
  24. correct action in that case is to change the program so that it is exactly what
  25. it is supposed to be. Unfortunately, sometimes the symptoms of a bug are only
  26. detected when the system is running and at this point no code changes are possible.</p>
  27. <p>In contrast, a failure is when a correct function in a correct program reflects
  28. some disappointing behavior in the environment. The correct action in that case
  29. is for the program to take a control path different than usual, which will likely
  30. cancel some operations and will likely result in different communication with the
  31. outside world.</p>
  32. <p>Symptoms of bugs can sometimes be detected during compilation or static program
  33. analysis or at run-time when observing certain values of objects that are declared
  34. never to be valid at certain points. One classical example is passing a null pointer
  35. to functions that expect a pointer to a valid object:</p>
  36. <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">int</span> <span class="nf">f</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span> <span class="n">pi</span><span class="p">)</span> <span class="c1">// expects: pi != nullptr
  37. </span><span class="c1"></span><span class="p">{</span>
  38. <span class="k">return</span> <span class="o">*</span><span class="n">pi</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  39. <span class="p">}</span>
  40. </code></pre></div>
  41. <p>Passing a null pointer where it is not expected is so common a bug that tools
  42. are very good at finding them. For instance, static analyzers will usually detect
  43. it without even executing your code. Similarly, tools like undefined behavior
  44. sanitizers will compile a code as the one above so that a safety check is performed
  45. to check if the pointer is null, and an error message will be logged and program
  46. optionally terminated.</p>
  47. <p>More, compilers can perform optimizations based on undefined behavior caused by
  48. dereferencing a null pointer. In the following code:</p>
  49. <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span> <span class="n">pi</span><span class="p">)</span> <span class="c1">// expects: pi != nullptr
  50. </span><span class="c1"></span><span class="p">{</span>
  51. <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="o">*</span><span class="n">pi</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  52. <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="p">(</span><span class="n">pi</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span> <span class="o">?</span> <span class="mi">1</span> <span class="o">:</span> <span class="mi">0</span><span class="p">;</span>
  53. <span class="k">return</span> <span class="p">{</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">};</span>
  54. <span class="p">}</span>
  55. </code></pre></div>
  56. <p>The compiler can see that if <code>pi</code> is null, the program would have undefined
  57. behavior. Since undefined behavior is required by the C++ standard to never
  58. be the programmer&rsquo;s intention, the compiler
  59. assumes that apparently this function is never called with <code>pi == nullptr</code>. If so,
  60. <code>j</code> is always <code>0</code> and the code can be transformed to a faster one:</p>
  61. <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="n">pair</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="kt">int</span><span class="o">&gt;</span> <span class="n">g</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span> <span class="n">pi</span><span class="p">)</span> <span class="c1">// expects: pi != nullptr
  62. </span><span class="c1"></span><span class="p">{</span>
  63. <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="o">*</span><span class="n">pi</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  64. <span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  65. <span class="k">return</span> <span class="p">{</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">};</span>
  66. <span class="p">}</span>
  67. </code></pre></div>
  68. <p>Functions like the one above that declare that certain values of input parameters
  69. must not be passed to them are said to have a <em>narrow contract</em>.</p>
  70. <p>Compilers give you non-standard tools to tell them about narrow contracts, so
  71. that they can detect it and make use of it the same way as they are detecting
  72. invalid null pointers. For instance, if a function in your library takes an <code>int</code>
  73. and declares that the value of this <code>int</code> must never be negative. You can use
  74. <code>__builtin_trap()</code> available in GCC and clang:</p>
  75. <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">void</span> <span class="nf">h</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="c1">// expects: i &gt;= 0
  76. </span><span class="c1"></span><span class="p">{</span>
  77. <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">__builtin_trap</span><span class="p">();</span>
  78. <span class="c1">// normal program logic follows ...
  79. </span><span class="c1"></span><span class="p">}</span>
  80. </code></pre></div>
  81. <p>This instruction when hit, causes the program to exit abnormally, which means:</p>
  82. <ul>
  83. <li>a debugger can be launched,</li>
  84. <li>static analyzer can warn you if it can detect a program flow that reaches this
  85. point,</li>
  86. <li>UB-sanitizer can log error message when it hits it.</li>
  87. </ul>
  88. <p>Another tool you could use is <code>__builtin_unreachable()</code>, also available in GCC
  89. and clang:</p>
  90. <div class="highlight"><pre class="chroma"><code class="language-c++" data-lang="c++"><span class="kt">void</span> <span class="nf">h</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="p">)</span> <span class="c1">// expects: i &gt;= 0
  91. </span><span class="c1"></span><span class="p">{</span>
  92. <span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="n">__builtin_unreachable</span><span class="p">();</span>
  93. <span class="c1">// normal program logic follows ...
  94. </span><span class="c1"></span><span class="p">}</span>
  95. </code></pre></div>
  96. <p>This gives a hint to the tools: the programmer guarantees that the program flow
  97. will never reach to the point of executing it. In other words, it is undefined
  98. behavior if control reaches this point. Compiler and other tools can take this
  99. for granted. This way they can deduce that expression <code>i &lt; 0</code> will never be true,
  100. and they can further use this assumption to issue warnings or to optimize the code.
  101. UB-sanitizers can use it to inject a log message and terminate if this point is
  102. nonetheless reached.</p>
  103. <p>Allowing for some input values to be invalid works similarly to cyclic redundancy
  104. checks. It allows for the possibility to observe the symptoms of the bugs (not
  105. the bugs themselves), and if the symptom is revealed the hunt for the bug can start.
  106. This is not only tools that can now easily detect symptoms of bugs, but also
  107. humans during the code review. A reviewer can now say, &ldquo;hey, function <code>h()</code> is
  108. expecting a non-negative value, but this <code>i</code> is actually <code>-1</code>; maybe you wanted
  109. to pass <code>j</code> instead?&ldquo;.</p>
  110. </div><p><small>Last revised: April 26, 2019 at 17:43:41 &#43;0200</small></p>
  111. <hr>
  112. <div class="spirit-nav">
  113. <a accesskey="p" href="../motivation/plug_error_code2.html"><img src="../images/prev.png" alt="Prev"></a>
  114. <a accesskey="u" href="../motivation.html"><img src="../images/up.png" alt="Up"></a>
  115. <a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../tutorial.html"><img src="../images/next.png" alt="Next"></a></div></body>
  116. </html>