Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #150688

Re: "How one word broke C"

From David Brown <david.brown@hesbynett.no>
Newsgroups comp.lang.c
Subject Re: "How one word broke C"
Date 2020-03-19 15:02 +0100
Organization A noiseless patient Spider
Message-ID <r4vu10$dt$1@dont-email.me> (permalink)
References <r4r8ev$8ba$1@dont-email.me> <91u7kg-ap03.ln1@mail.home.palmen-it.de> <r4u0m5$721$1@dont-email.me> <brjakg-hlj2.ln1@mail.home.palmen-it.de>

Show all headers | View raw


On 18/03/2020 23:27, Felix Palmen wrote:
> * David Brown <david.brown@hesbynett.no>:
>> You are imagining that undefined behaviour is a "cost" - it is not.  It
>> is a bonus - a benefit that C and C++ programmers get, that programmers
>> of other languages often do not have.
> 
> No, it is a cost paid for a bonus.

(I'm concerned here with undefined behaviour at run-time, rather than 
things like declaring a function in one place and defining it in another 
place with different parameters.  Good code structure and compiler flags 
eliminate that kind of thing for the most part.)


There is no cost.

Look, your aim is to write bug-free code, agreed?

So the two concerns are how does UB affect correct code once it is 
written, and how does UB affect finding or avoiding the bugs in order to 
get correct code?

First, consider correct code.  This code does not let signed integer 
operations overflow, since any answer would be wrong.  It does not 
access arrays out of bounds, since that could not possibly be correct. 
It does not dereference null pointers, or free pointers twice, or use 
any function or operator in the language outside of the specifications 
(given by the standards and the implementation).  What does it matter if 
dereferencing a null pointer launches nasal demons?  Nothing at all, 
since your code never dereferences a null pointer.  UB is /zero/ cost 
for correct code.  (And because it allows more optimisations, it is a 
positive benefit.)

Then consider finding bugs.  Undefined behaviour is always a bug - and 
thus compilers and analysis tools can complain about them and give 
warnings about them.  Of course no tool can find every fault, but they 
are getting steadily better at finding more.  And you can have run-time 
tools such as specialised memory allocators and "sanitizers" that add 
run-time checks of various types in order to catch a lot of undefined 
behaviour.

If the behaviour were defined, the compiler (and other static and 
run-time diagnostic tools) would have to follow that definition - and it 
cannot distinguish between coding errors and intentional code.  If your 
calculations overflow, but the language says that adding big positive 
numbers should give a negative number, that's what you get - and your 
tools have no option to add a run-time check, because the ridiculous 
behaviour is "correct" according to the language.



There is one other situation in the middle here - when you think your 
code is correct, and you release it, but there is accidental undefined 
behaviour left.  What happens if you hit it?  Nasal demons, in theory. 
In practice, it might lead to a crash (typical for pointer problems), it 
might hit a "undefined behaviour" or breakpoint opcode (contrary to 
conspiracy theories, compilers try to be helpful when dealing with UB), 
or it might carry on with odd results that cause trouble in different 
places.  What would happen in a programming language with defined 
handling of these same problems?  It might throw an error or exception, 
leading to a crash or halt of the program (remember we are talking about 
problems that you haven't foreseen), or it might carry on with odd 
behaviour, leading to trouble in different places later on.


The UB in C and C++ is either a benefit, or no worse than languages 
(like Java) that give defined behaviour to these things.

If you can't handle this, or don't want to handle it, you need to use a 
language which avoids the kind of situations that are UB in C - not one 
that glosses over them.  That means a language that has all the run-time 
tests in place all the time, and which does not allow free pointers and 
other "dangerous" concepts.  You need a language like Python where 
integers grow, rather than overflow, and there are no pointers.

> 
>> The fact that things like out-of-bounds array access, signed integer
>> overflow, reading uninitialised local variables, etc., is undefined
>> behaviour is a /good/ thing.  It makes it easier to write good, correct
>> programs.
> 
> That's really wishful thinking. Don't get me wrong, I like C the way it
> is and I'm quite happy with the fact that it has UB. But if anything, it
> makes it /harder/ to write correct programs, because:
> 
>> This is because doing any of these things, in any language,
>> is (almost invariably) a mistake.  Languages which define a behaviour
>> here are just sweeping the problem under a rug.
> 
> They define the behavior to reliably indicate an error (fail fast).
> That's quite the opposite of sweeping. An incorrect C program OTOH could
> just work as you expect (and it often does exactly that).

Often they don't give an error - they just continue regardless of the 
nonsense in progress.  A prime example is Java's wrapping signed 
integers.  And when you are dealing with unexpected errors, the result 
is generally a crash whether it is from the language run-time or from 
the OS.  If you accidentally dereference a null pointer, it makes very 
little difference to the user whether they see a message saying your Ada 
program has thrown an uncaught exception, or your C program has caused a 
segmentation fault.

All you can be sure about is when the behaviour is defined by the 
language, your chances of finding it with static analysis are nil - with 
C, you might have /some/ chance at least.

> 
> If there's anything good about UB with respect to writing correct
> programs, it's that it teaches you to be extra careful.

That's another bonus.

> 
>> Some might give you a
>> run-time error when these happen - then you have a chance to find them,
>> but only if you are lucky during testing.
> 
> You shouldn't have to "be lucky" if your test cases are written
> properly. But with C, even full test coverage is no guarantee, thanks to
> UB.

If you can actually get full test coverage, then UB is not a hinder. 
Usually, however, you can't - and tests are a matter of luck.  Testing 
can prove the presence of bugs, but not the absence - anyone who tells 
you their code is "fully tested" is almost certainly exaggerating or 
mistaken.  (I am not dismissing testing - it is vital in code development.)

> 
>> With C and C++, many of these
>> can be spotted by the compiler (or more advanced static analysis tools)
>> so you are warned as early as possible.
> 
> For varying definitions of "many". I assume you are familiar with the
> halting problem? A good compiler or analysis tool is great, of course
> everyone prefers getting errors at build time. But this applies to any
> language, and it's always impossible to fully analyze a program without
> running it, theoretical proof exists. So, do you prefer those errors
> that can't be found at build time to potentially stay hidden or to
> reliably fail at runtime?

"Reliable failure" is an oxymoron.

Yes of course static analysis is always limited - even if tools are 
getting steadily better.  But I prefer "finds some errors during 
compilation" over "ignores all errors until runtime".

I prefer code to be designed in a way that avoids the risk of the 
failures.  And I think it is a good think to put in appropriate manual 
checks where you are not sure (asserts are popular in C - and much more 
flexible than any language-based runtime checks), and to test code with 
sanitizers or debug libraries.

I don't think it would do much harm for people to release some C code 
with certain kinds of run-time checks still enabled (with sanitizers). 
With UB, you have that option.

I also don't think C is an appropriate choice of language for many 
people, and for a lot of code that is currently written in it.  Trying 
to reduce UB in C would be the wrong way to reduce errors - the aim 
should be in getting people who write code with UB to use safer, simpler 
(but less efficient) languages instead.

> 
>> Even worse are languages that define the behaviour of signed integer
>> overflow as wrapping - that hides the errors in the code as much as
>> possible.
> 
> That would be a pretty stupid design decision (which language does
> that?), but comes close to what some C implementations (legally, because
> of UB) do.
> 

Java has wrapped signed integer arithmetic, as does unchecked C#. 
(Detection and trapping would cripple efficiency of arithmetic code.)

Wrapping behaviour is also almost invariably the suggestion people give 
when they say they want defined behaviour for integer overflow in C.  It 
is one of the least inefficient choices, but also the least helpful.

Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

"How one word broke C" Lynn McGuire <lynnmcguire5@gmail.com> - 2020-03-17 14:29 -0500
  Re: "How one word broke C" Real Troll <Real.Troll@Trolls.com> - 2020-03-17 15:40 -0400
    Re: "How one word broke C" John Bode <jfbode1029@gmail.com> - 2020-03-19 11:57 -0700
      Re: "How one word broke C" James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-19 18:20 -0400
  Re: "How one word broke C" Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2020-03-17 13:39 -0700
    Re: "How one word broke C" Jorgen Grahn <grahn+nntp@snipabacken.se> - 2020-03-17 21:55 +0000
  Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-17 23:02 +0100
    Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-17 21:57 -0400
      Re: "How one word broke C" Dan Purgert <dan@djph.net> - 2020-03-18 11:02 +0000
        Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-18 08:58 -0400
          Re: "How one word broke C" Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-03-18 06:04 -0700
            Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-18 09:53 -0400
          Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-18 14:46 +0100
            Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-19 08:55 -0400
      Re: "How one word broke C" Philipp Klaus Krause <pkk@spth.de> - 2020-03-18 18:21 +0100
        Re: "How one word broke C" already5chosen@yahoo.com - 2020-03-18 12:11 -0700
          Re: "How one word broke C" Philipp Klaus Krause <pkk@spth.de> - 2020-03-18 21:06 +0100
            Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-18 22:43 -0400
              Re: "How one word broke C" Tim Rentsch <tr.17687@z991.linuxsc.com> - 2020-03-27 07:18 -0700
        Re: "How one word broke C" Dan Purgert <dan@djph.net> - 2020-03-19 01:40 +0000
      Re: "How one word broke C" Eli the Bearded <*@eli.users.panix.com> - 2020-03-18 19:12 +0000
        Re: "How one word broke C" Philipp Klaus Krause <pkk@spth.de> - 2020-03-18 21:09 +0100
    Re: "How one word broke C" David Brown <david.brown@hesbynett.no> - 2020-03-18 21:35 +0100
      Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-18 23:27 +0100
        Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-19 08:57 -0400
          Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-19 15:00 +0100
        Re: "How one word broke C" David Brown <david.brown@hesbynett.no> - 2020-03-19 15:02 +0100
          Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-19 15:10 +0100
            Re: "How one word broke C" gazelle@shell.xmission.com (Kenny McCormack) - 2020-03-19 14:34 +0000
              Re: "How one word broke C" Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-03-19 07:44 -0700
                Re: "How one word broke C" Jorgen Grahn <grahn+nntp@snipabacken.se> - 2020-03-19 14:57 +0000
                Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-19 15:58 +0100
                Re: "How one word broke C" David Brown <david.brown@hesbynett.no> - 2020-03-19 16:26 +0100
              Re: "How one word broke C" David Brown <david.brown@hesbynett.no> - 2020-03-19 16:08 +0100
                Troll, gadfly, whatever... (Was: "How one word broke C") gazelle@shell.xmission.com (Kenny McCormack) - 2020-03-21 11:08 +0000
                Re: Troll, gadfly, whatever... (Was: "How one word broke C") Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2020-03-21 04:50 -0700
            Re: "How one word broke C" David Brown <david.brown@hesbynett.no> - 2020-03-19 16:04 +0100
              Re: "How one word broke C" felix@palmen-it.de (Felix Palmen) - 2020-03-19 16:16 +0100
                Re: "How one word broke C" Richard Damon <Richard@Damon-Family.org> - 2020-03-19 23:36 -0400
          Re: "How one word broke C" James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-19 18:13 -0400
  Re: "How one word broke C" Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2020-03-17 19:43 -0600
    Re: "How one word broke C" John Bode <jfbode1029@gmail.com> - 2020-03-24 16:07 -0700
  Re: "How one word broke C" James Kuyper <jameskuyper@alumni.caltech.edu> - 2020-03-24 19:41 -0400

csiph-web