top | item 39590114

How can C Programs be so Reliable? (2008)

78 points| contr-error | 2 years ago |tratt.net

90 comments

order

lelanthran|2 years ago

I think every graduating student should work on a non-trivial application in plain C for a year before moving on to another language.

It makes you exceptionally paranoid about failure states and practically requires a bit of thought and planning before attempting any non-trivial change.

The mindset of "it's fine to ignore all error conditions and let the default exception handler print a stack trace to the user" results in software that is annoying to the user.

lifthrasiir|2 years ago

While I agree with last two paragraphs, C is not good even for that purpose because it doesn't give any tool to manage them. An effective C education should really be paired with various static analyses and formal verification strategies.

begueradj|2 years ago

When I was a student, I struggled learning algorithmic because we had to code in C. Luckily we had a wonderful teacher who listened to us, students, and switched his teaching to Pascal. That was a big relief to all of us.

I believe language like Pascal and Python are good to initiate you to algorithmic. After that, I agree you would need to dive into languages such as C, Rust and why not Assembly language to have a better understanding of your machine.

In our case, after one year of coding with Pascal, we spent the remaining years in focusing on C and C++ (Builder)

After that, it's time to move to pragmatic choices (job market requirements in terms ofdevelopment stack)

masfoobar|2 years ago

C was the first language covered at my University back in the early 2000s

It was not a problem for me as I was learning Turbo C and Visual C++ 5/6.0 a year or two beforehand.

Everyone else in the class, though, were sooooo frustrated with their "89 errors, 103 Warnings" all because they forgot to add a semicolon in the code.

Truth is they were not getting anywhere to understanding how to write or care about the quality of the code.. leading to proper planning, etc. They would keep changing something to reduce the errors/warnings.

Personally, I think every person has their own journey into the world of programming. For me, I was happy for it to be C, with a bit of Pascal and Visual Basic. For someone else, perhaps Scheme and Javascript. Another maybe Java.

Some developers/programmers, in my opinion, are not for C. controversial ... I know.

ParetoOptimal|2 years ago

I think writing in Haskell or Rust and using ADTs and pattern matching with exhaustivity checking does the same thing.

Gigachad|2 years ago

Rust is better for this since your program won’t even compile until you’ve handled those error states.

kazinator|2 years ago

Reliable is not the same as portable, which is not the same as well-defined according to the language spec.

The consequences of doing something incorrect or nonportable is sometimes that the expected behavior occurs. This can be validated by testing on the couple of platforms (or just one) that the program supports, and kept working.

Another thing we need to consider is that reliable is not the same thing as robust, let alone secure. A program that appears reliable to a user who uses it "as directed", giving it the expected kinds of inputs, will not necessarily appear reliable to a tester looking for ways to break it, or to a cracker trying to exploit it.

A truly reliable program not only handles all its functional use cases according to its requirements, but is impervious to deliberate misuse, no matter how clever.

Security flaws are found in reliable, well-debugged programs used in production by millions.

msla|2 years ago

> The consequences of doing something incorrect or nonportable is sometimes that the expected behavior occurs. This can be validated by testing on the couple of platforms (or just one) that the program supports, and kept working.

A practical example of this is word size issues: A program that casts pointers to ints everywhere is perfectly reliable on 32-bit machines, but it will die horribly on any LP64 machine, which are most 64-bit machines. Related are endianness issues, which is why projects have tended to stop supporting big-endian systems: They're just too rare to scrounge up anymore, and unless you're actively testing on them, bugs can slip in which will not be caught on little-endian hardware.

Similarly, OS developers stop supporting architectures when they can no longer find working examples of them. This is because emulators have bugs, and without a source of truth (working hardware) it's very hard to determine if a bug you just found is in the OS or the emulator; add unreliable hardware to that and things just get worse. Bob Supnik (former DEC VP, creator of SimH) has a PDF:

http://simh.trailing-edge.com/docs/bugfeature.pdf

norir|2 years ago

C is horrible for exploratory programming but is acceptable if you already know how to solve the problem. If one uses enums for errors, then the compiler can check for you that all edge cases are handled. You can log an error and exit(1) for unhandled cases during development which makes it feasible to turn on -Werror but not have to implement every edge case up front.

You can do the same thing with tagged unions to implement a poor man's sum types. It is significantly more verbose than in a language that has syntactic support for this, but you get similar compile time safety guarantees.

flohofwoe|2 years ago

> C is horrible for exploratory programming...

Completely opposite experience here. C is great for explorative coding because it's just structs and functions.

There's no agonizing about whether some piece of code should go here or better there, wrapped in this or that concept or high level abstraction.

Instead you start with an empty screen and incrementally build your ideas from small building blocks, much like in Lisp or Forth.

whiterknight|2 years ago

> C is horrible for exploratory programming

Completely disagree. The lack of screwing around selecting abstractions forces you to make something productive right away and not stress about refactor.

insomagent|2 years ago

If you're talking about something like a web server, then sure. If you're talking about kernel hacking, then I completely disagree.

rramadass|2 years ago

Though not specific to C language, C.A.R Hoare's Retrospective: An Axiomatic Basis for Computer Programming provides insight on why Software is so reliable in spite of a lack of application of formal verification methods.

Retrospective: https://cacm.acm.org/opinion/retrospective-an-axiomatic-basi...

Here is a pdf of the retrospective along with the original paper : https://harrymoreno.com/assets/greatPapersInCompSci/2.2_-_An...

begueradj|2 years ago

The author started by seriously admitting the drawbacks of C. Then, somehow, he says thanks to those flaws he has to pay higher attention when building software in C, he created very reliable tools.

That's something I can understand because when I wanted to buy a motorbike I was advised to ride a bicycle first since it's more difficult to control. Except that the White House called recently for companies to not use non memory safe languages such as C to build software.

mgaunard|2 years ago

That's not what the white house said and they're not an authority in software engineering anyway.

Just sensationalist journalism.

bdjsiqoocwk|2 years ago

The white house, the thought leaders in software engineering.

tored|2 years ago

I built a house by only using a broken hammer, that made the house better because I needed to spend more time to handle the broken hammer correctly.

quelsolaar|2 years ago

C suffers from a terrible case of survivor bias. C is so effective for writing all of the most critical software, that almost all software people trust is written in C. Therefore almost all critical vulnerabilities are found in C code.

cjfd|2 years ago

I think the reliability gap is in statically typed, compiled languages versus dynamically typed languages. I think C++ is a good combination of both worlds. You don't have to type quite as much for error checking an manual management and you get a correctly typed program by default.

xigoi|2 years ago

Static typing is useless without strict typing. Knowing the type of everything won’t save you if you can multiply a pointer by an integer and use the result as a file handle.

BobbyTables2|2 years ago

Until one writes a nontrivial program that properly handles -EINTR errors on every possible point, I don’t anyone should brag about their error handing prowess.

It is also hard to handle errors more meaningfully than instantly terminating the process at the first whif of something going sideways.

And once you do write such a thing, try making automated tests to exercise it!!

How many programs actually check the return value of close() ?

Sure, this sounds a bit Linux/POSIX specific. There are only a few billion devises running such code, perhaps I’m overreacting…

nighthawk454|2 years ago

Is the mindset of exception handling so different than robust C code? In both cases you have to choose to diligently handle errors and check the code/docs for all cases that can come up. Writing code with the occasional try/catch block isn't too different from writing C and not checking error conditions

nicklecompte|2 years ago

> Writing code with the occasional try/catch block isn't too different from writing C and not checking error conditions

I think a critical difference is that in C the program is more liable to simply crash if errors aren't correctly handled, whereas in Java/Python/etc the program can just log a stack trace and keep on truckin', even if the bug is actually quite severe. In some cases a crash is preferable - e.g. if something goes wrong in a text editor while saving data, it's a lot better for the user if the program crashes versus the alternative where the editor runs as normal but saving doesn't work. Crashes in C also bring more urgency for developers to actually fix the bug compared to a try/catch in Python that simply buries it "until I get a chance to debug it properly." (But crashing also leads to a lot of frustration when the error wasn't that important and the C program should have just kept going.)

kazinator|2 years ago

If you work with enough C code, you will come across exception handling. I made an exception handling library long ago. It lives mainly in Wireshark.

tored|2 years ago

This text doesn’t make much sense, on the one hand the author argues that software written in C is robust, on the other hand the author admits that he has unknown bugs lurking in his own project.

One bug took several months to track down. This is cognitive dissonance at its finest.

AtlasBarfed|2 years ago

1) were C programmers "better"? In sum total, pretty much.

2) C programs, at least the ones we use now, are a product of a lot of use and debugging

3) It didn't take too many debugging sessions as a C programmer to learn to program a bit more carefully.

4) and the more it gets used, the more error codes it encounters, and the more robust the handling gets. I think a dirty secret of software engineering isn't that the most complicated/heavily used code gets the most and most useful comments, it's that it also get the most error handling/detection code, and for the vast majority of non-core loop code: error handling ..isn't.

wiseowise|2 years ago

> were C programmers "better"? In sum total, pretty much

No. Original programmers that just happened to use C were better, not the other way around.