<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Wed, Mar 14, 2018 at 11:06 PM Hyman Rosen &lt;<a href="mailto:hyman.rosen@gmail.com" target="_blank">hyman.rosen@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Mar 14, 2018 at 7:10 PM, Nick Lewycky <span dir="ltr">&lt;<a href="mailto:nlewycky@google.com" target="_blank">nlewycky@google.com</a>&gt;</span> wrote:<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>The compiler is &quot;trusting the programmer&quot; the programmer to never run undefined behaviour.</div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> The language trusts the programmer in the sense that casts are not checked.</div></div></div></blockquote><div><br>The concept of undefined behavior is erroneous except for things like<br>dereferencing pointers that do not point into owned memory, where there<br>is literally no meaningful thing that can happen.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>I don&#39;t see anything in your link <span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">that defends the interpretation of</span> &quot;trust the programmer&quot; as </div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> meaning that compiler should emit obvious assembly. Do you have a supplemental reference?</div></div></div></blockquote><div><br>&quot;Trust the programmer&quot; must mean to make the actions of the compiled code<br>follow the actions of the written code, or act as if it does.  Anything else is<br>literally not trusting the programmer.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>There are a large number of reasons that a compiler should not emit the obvious operations on ordinary 2&#39;s complement hardware, as I have wide freedom to choose the contents of the &quot;...&quot;. It ranges from the very obvious (&quot;x = 0;&quot; so constant folding occurs and blocks emission of the negation, or &#39;x&#39; is never used again so dead code elimination blocks emission of the negation) to the less obvious (~x is used in multiple calculations in different expressions) to the downright hard to reason about.</div></div></div></blockquote><div><br>The compiler still has as-if latitude.  As-if transformations maintain the actions<br>of the written program.  Assuming undefined behavior doesn&#39;t happen does not.<br></div></div></div></div></blockquote><div><br></div><div>As-if transformations maintain the actions of the written program under the assumption that undefined behaviour does not occur. The two are fundamentally intertwined.</div><div><br></div><div>Here&#39;s a few thought experiments:</div><div>1. may a compiler replace &quot;x+1+1&quot; with &quot;x+2&quot; assuming x is an int? The two produce the same results in all cases, even if you choose wrapping, overflowing, or saturating arithmetic. Suppose you are the vendor of a compiler and the user complains &quot;I know the add instruction encoding on my CPU, I crafted a pointer to my instruction stream, I failed to find two add-with-constant-1 instructions&quot;. With what rules would you justify the transformation &quot;x+1+1&quot; to &quot;x+2&quot;? Currently the answer is that there is no means to form such a pointer: any attempt to do so necessarily executes UB, therefore we assume it has not occurred.</div><div>2. may a compiler remove &quot;int i = *ptr;&quot; where variable &#39;i&#39; is subsequently unused? What if &#39;ptr&#39; is unaligned or null? Suppose you are the vendor of a compiler and the user complains, &quot;the underlying hardware traps on misaligned/null pointers, I expected this execution to trap with the appropriate type of trap&quot;. With what rules would you justify deleting this dead code? Currently the answer is that null pointer dereference and misaligned access (well, access of wrong type) are unde</div><div>3. may a compiler remove &quot;int i = 0xdeadbeef;&quot; where &#39;i&#39; is unused? <span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">Suppose you are the vendor of a compiler and the user complains &quot;I put that value in a stack variable so that I could look through my stack for the magic number and know where I was in the stack&quot;. With what rules would you justify deleting an unused variable? Currently the answer is that there is no means to form such a pointer: any attempt to do so necessarily executes UB, therefore we assume it has not occurred.</span></div><div>3a) A variation on question 3 is to put two variable declarations inside two arms of an if/else, assigning them to different values. Today every compiler will allocate space on the stack for all variables once as part of function prologue, except for functions with VLAs or dynamic alloca calls. What if the user looks up the stack to determine which side of the if/else they were being called from?</div><div><br></div><div>Today, all these optimizations are justified by the fact that any attempt to observe the difference before and after optimization must necessarily execute undefined behaviour, and executing undefined behaviour is a priori assumed to be impossible.<br></div><div><br></div><div>It&#39;s possible that there&#39;s another way to show that these and other optimizations are valid, but I would need to see a proposal on how to do that. I&#39;ve tried to create one myself and failed. Frankly, I&#39;m starting to believe that our current situation with UB really is the best possible design choice.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>The other reason to do something other than emit the &quot;obvious operations&quot; is to detect unintended overflow. F<span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">or one large industry example </span>Android security is deploying unsigned integer overflow checking: <a href="https://android-developers.googleblog.com/2016/05/hardening-media-stack.html" target="_blank">https://android-developers.googleblog.com/2016/05/hardening-media-stack.html</a> . Instead of overflow, their compiler emits an overflow check and trap instruction.</div></div></div></blockquote><div><br>That&#39;s fine.  Ada generated exceptions on overflow and other subtype constraint<br>violations from its inception.  It simply means that the underlying computer isn&#39;t a<br>2&#39;s-complement arithmetic machine, and programs written for 2&#39;s-complement<br>arithmetic won&#39;t work there.  C and C++ programs do not have to be portable to<br>be valid.  It&#39;s going to be up to the users of the non-2&#39;s-complement platform to<br>decide if it fits their needs.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">What semantics does &quot;issue the underlying machine instructions and return whatever result they provide&quot; have?</div></div></div></div></blockquote><div><br>The compiler has a mapping from abstract machine to its target computer,<br>whereby it represents program objects as machine objects.  The target computer<br>has its own semantics for arithmetic operations.  By far the most common<br>semantics for machine integer arithmetic is fixed-width 2&#39;s-complement, and<br>when that&#39;s the case, that&#39;s what the quoted phrase means - do the arithmetic<br>in 2&#39;s-complement and return the result.<br><br>That is what the standard explicitly requires everywhere for atomic ints, so I don&#39;t<br>see why you would find this surprising or difficult.<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"> What about template non-type arguments? Constant expression evaluation? Used in the size of an array?</div></div></div></div></blockquote><div><br>What is difficult to understand?  For those things, the compiler&#39;s target platform<br>is an artificial target platform embedded within the compiler itself.  For ease of<br>programmer understanding, that platform should behave in the same way as the<br>actual target platform.<br></div></div></div></div></blockquote><div><br></div><div>The difficulty is that the compiler would then need to have a processor emulator for the target platform. This is not presently how compilers work. It&#39;s possible that this emulator could in fact be made simple by dealing only with the subset of cases that the compiler itself relies on. Presently compilers simulate execution on top of a single abstract machine described in the language specification, and produce programs with equivalent behaviour to the abstract machine. The details of the underlying machine *largely* don&#39;t trickle upwards to affect evaluation in the abstract machine (except when it does, like in sizeof).</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">What if the compiler uses &quot;whatever the machine does&quot; when determining the size of an array as part of compilation, then we copy the resulting program to a different computer that claims to have the same ISA, but where &quot;whatever that machine does&quot; happens to be different. (This situation would be surprising for integer arithmetic, but did occur for x86 floating point arithmetic.) Are you okay with the compiler evaluating one size for an array at compile time, but calculating a different size for the array at run time?</div></div></div></div></blockquote><div><br>As I said, it would be extremely confusing for the compiler to do that, so it shouldn&#39;t.<br><br>But C and C++ already have the maximum possible stupidity of allowing floating-point<br>expressions to be calculated at different precisions, so that it is literally possible for the<br>expression <font face="monospace, monospace">a + b == a + b</font> to be false when the operands are normal floating-point<br>values.  And everyone seems to accept that with equanimity.  Optimization, naturally.<br></div></div></div></div></blockquote><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">What if I tell you, for the sake of argument, that compilers today are already following</div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"> your proposed rule: since you<span style="font-family:arial,sans-serif;font-size:small"> </span>didn&#39;t specify which instructions to issue, you have no<span style="font-family:arial,sans-serif;font-size:small"> </span></div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"> standing to complain about the instructions the compiler chose.</div></div></div></div></blockquote><div><br>You don&#39;t get to tell me whether or not I have standing.</div></div></div></div></blockquote><div><br></div><div>I&#39;m not clever enough to see what possible argument you could make. Maybe you can suggest something? The setup is that you&#39;ve written a program and the compiler emits assembly you didn&#39;t consider &quot;the obvious lowering&quot;. You complain to the compiler authors and they say &quot;yes, this is the obvious lowering&quot;. Now how would you proceed? T<span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">here&#39;s no specification to reference to determine whether the compiler did emit the &quot;obvious lowering&quot; or not, </span>that&#39;s what I meant by &quot;not having standing&quot;.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>  I&#39;m going to complain about<br>this forever, so that all the people who made the bad decisions will feel bad about<br>themselves, and not sleep at night because of all the grief they&#39;ve caused programmers.<br></div></div></div></div></blockquote><div><br></div><div>I agree! But I arrived at the opposite conclusion. I wish compilers exploited undefined behaviour to the fullest extent, and I wish they had started doing more of it longer ago. If only the optimizer broke people&#39;s programs the first time they ran them, programmers would have noticed the failure sooner and not proceeded with their buggy code. The sooner the optimizers get better at breaking buggy code in mean and nasty ways, the sooner we&#39;ll stop writing even more code with these kinds of bugs in it. I would rather deal with that pain now so that we have a better world tomorrow.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>You also don&#39;t get to be immunized from critics who weren&#39;t there when decisions were<br>made.  Learning from bad decisions of the past helps prevent bad decisions in the future,<br>for those willing to learn.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial"> Can you fix this without adding a listing of CPU instructions to the language standard</div></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><div style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial">and without fully defining it?</div></div></div></div></blockquote><div><br>I don&#39;t need to.  The C++ Standard already specifies that atomic integers obey the rules<br>of 2&#39;s-complement arithmetic, and it doesn&#39;t spell out what those rules are.<br></div></div></div></div></blockquote><div><br></div><div>I would consider it shall &quot;obey the rules of 2&#39;s complement arithmetic&quot; to be fully defined, as 1&#39;s complement machines would have to simulate 2&#39;s complement arithmetic. (Offhand, I think this is what happens with atomics today; 1&#39;s complement machines are expected to use a library call to implement the atomic and ensure 2&#39;s complement?)</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Indirecting a pointer should mean &quot;refer to<br>the memory pointed to as if there is an object there of the pointer type&quot; and<br>should be undefined only if the pointer does not point to correctly aligned<br>memory owned by the (entire) program.  And so on.<br></div></div></div></div></blockquote><div><br></div></span><div>Suppose I have a function with two local variables, &quot;int x, y;&quot; and I take &amp;x, I can use</div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>x[1] (or x[-1]) to make changes to &#39;y&#39;?</div></div></div></blockquote><div><br>Yes, provided you know that the memory layout corresponds to that.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>And similarly, I can construct a pointer to stack variables <span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">in another call stack frame</span> </div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div><span style="color:rgb(34,34,34);font-family:sans-serif;font-size:13px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"> </span>whose address was never taken? As long as I can cast the right integer to a pointer?</div></div></div></blockquote><div><br>Yes.<br><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Given these rules, when would it be valid to move automatic local variables into registers?</div></div></div></blockquote><div><br>Always.  If a variable is not in memory, then a pointer can&#39;t be made to point to it,<br>no matter how the pointer is manipulated.  As I said, you must know the memory<br>layout in order to do tricks with pointers.</div></div></div></div></blockquote><div><br></div><div>The as-if rule only applies if the program can not tell the different between the before program and the after program. If you can form pointers this way, the program now has a way to observe the difference, revoking the compiler&#39;s permission to perform the optimization. With these rules, the compiler may no longer remove stack variables from the stack, or reorder them, etc. I don&#39;t think that&#39;s the language we want. Do you have a suggestion on how to both permit the construction of such pointers and also permit this optimization?</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>Only when there are no opaque pointers used and no opaque functions called?</div></div></div></blockquote><div><br>No, always.  In fact, that&#39;s why we had the <font face="monospace, monospace">register</font> keyword.  That told the compiler<br>that the address of such variables could never be taken.</div></div></div></div></blockquote><div><br></div><div>I don&#39;t think C++ users want a language where copies of all automatic storage variables must be present on the stack.</div><div><br></div><div>There might be a market for a different language which really does behave that way, but I should point out that it&#39;s been tried. The proposal for Friendly C: <a href="https://blog.regehr.org/archives/1180" target="_blank">https://blog.regehr.org/archives/1180</a> and later The Problem with Friendly C: <a href="https://blog.regehr.org/archives/1287" target="_blank">https://blog.regehr.org/archives/1287</a> .</div><div><br></div><div>Nick</div><div><br></div></div></div>