Path: csiph.com!weretis.net!feeder6.news.weretis.net!feeder.usenetexpress.com!feeder-in1.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!news.iecc.com!.POSTED.news.iecc.com!nerds-end From: Andy Walker Newsgroups: comp.compilers Subject: Re: Optimization techniques and undefined behavior Date: Fri, 3 May 2019 13:29:38 +0100 Organization: Not very much Lines: 95 Sender: news@iecc.com Approved: comp.compilers@iecc.com Message-ID: <19-05-020@comp.compilers> References: <19-04-021@comp.compilers> <19-04-023@comp.compilers> <19-04-037@comp.compilers> <19-04-039@comp.compilers> <19-04-042@comp.compilers> <19-04-044@comp.compilers> <19-04-047@comp.compilers> <19-05-004@comp.compilers> <19-05-006@comp.compilers> <19-05-016@comp.compilers> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="7970"; mail-complaints-to="abuse@iecc.com" Keywords: errors, performance Posted-Date: 03 May 2019 13:56:51 EDT X-submission-address: compilers@iecc.com X-moderator-address: compilers-request@iecc.com X-FAQ-and-archives: http://compilers.iecc.com Content-Language: en-GB Xref: csiph.com comp.compilers:2255 On 03/05/2019 00:48, Bart wrote: >>> If you have two unknown values A and B, and need to multiply, you won't >>> know if the result will overflow. >>   int A := ..., B := ...; >>   int C := ( A = 0 | 0 |: abs B <= maxint % abs A | A*B | error (...); 0 ); > That sounds unmanageable Indeed, but it was a proof of concept. Obviously, you can tuck that line away either using a macro definition or as a function/operator. > (think about checks here: a*a+b*(c*d), and how > you might proceed from the error if not aborting) and inefficient if one > multiply turns into half a dozen operations including a divide. How quickly do you want your buggy results? If you have to write code to check, then it takes time, both to write and to execute. Yes, if you have a complicated expression, it takes lots of time to execute, and your program will run much more slowly. > If such overflow checks need to be routinely done, then it really needs > language support. If you want to regain efficiency, then it needs not language so much as hardware support. Yes, you then need a language hook into that hardware. Early computers/languages typically had statements something like on overflow goto l arrayboundcheck off to give the programmer fine control over the checks and what to do if the traps were sprung. But it really only works well if the hardware can generate an interrupt. > Otherwise it's probably best handled by a guard > function similar to what someone posted: >     if multiply_overflow(a,b) then >          print "Overflow" >     else >          c := a * b        # requires that a and b haven't changed >     end I would prefer "c := a &* b;" or similar, where "&*" is a "safe multiply" [which you can write yourself in languages that support user- defined operators]. So your example above becomes a &* a &+ b &* (c &* d) You can solve the "abort?" problem by having a procedure that is called when "&*" detects overflow. > This at least isolates the actual expression we want and leaves it readable. Yes, but, in the absence of hardware support, it's not going to be any more efficient than my code [or some near equivalent] above. >>      Of course, in the old days, compilers used to build in range >> checks on array indices and overflow checks on all arithmetic. > Did they? Certainly not any of mine (not really practical on tiny 8-bit > computers on which both the compiler and the program being developed had > to run). You're too young. C on a PDP-11/34 running Unix, in the mid-70s, was roughly the 10th serious language and the 5th computer/OS I used over 16 years or so, and the first that did not have array-bound checks and overflow checks compiled in and switched on by default. >>   A few >> still do, esp interpreters, but the God of Speed dictates that most >> languages in most circumstances don't.  We see the results in the huge >> amount of malware that exploits that failure. > I don't know how much that would help. And I think that if a program can > go seriously wrong through unchecked input, then that's a failure in > proper validation. It's rather sloppy to rely on a runtime check put > their by a compiler. Counsel of perfection. The reality is that every week I get bug fixes to major software on my computer that consists of cures for buffer over-runs, dereferencing null or dangling pointers, overflow conditions, race conditions, storage leakage, .... All of those can be exploited by carefully-crafted malware. All of them, except perhaps some race conditions, can be detected before the exploit by checks put there by a compiler. Most of the checks can be optimised away in well- written code for a decent language. > During development, yes, but perhaps not after a program is supposed to > be working. Dijkstra[?] wrote along the lines of "It's like wearing water wings to paddle around the swimming pool and discarding them when you swim out to sea". [I've looked for the exact quote, but can't find it.] -- Andy Walker, Nottingham.