Skip to content

Comment on Software Checklist

Comments

I think he's missing an important point. C should not be used for safety critical systems code if possible, period. A language that prevents those leaks should be employed in its place.

Checklists are good, but you need to enforce them. If such a language is used instead, these errors are impossible by design.

I think you're missing the point. Whether or not we're talking about C is a detail, what is more important is that the lessons we learn need to be encapsulated and encoded into procedures that everyone can apply and learn from.

Equivalent mistakes can be made in any language powerful enough to do real work. Off-by-one, behaving inappropriately on parameters outside those expected, lots of things can go wrong in any language. Capturing your knowledge in a form that can be used for testing is the idea, and that seems to be missing entirely from computing.

Languages can eliminate large classes of such mistakes.

Taking your own two examples: most off-by-one errors go away if you replace "for (i = 0; i < datalength; i++)" with "for i in data" or something like that; and by replacing < or <= comparisons with checks for range membership. A checklist might say - "don't have assignments in your if statement conditions like 'if (x=0)', it's risky"; but your language or tools around it may make it impossible to do it.

"Behaving inappropriately on parameters outside those expected" is correlated with the frequency of getting unexpected parameters. No static typing? You'll have to check at runtime if the parameters are of the type that you expect. Null/undefined values? Again, you may remember to check everywhere or the language can force you to check really every time, not almost every time. Niche languages like Eiffel can help you ensure that you know that the parameters are within the expected range, etc.

Capturing such knowledge and encoding in a way suitable for everyone is done in this way - it does break backward compatibility and requires rewriting code and abandoning libraries or even languages; but the checklist equivalent of "don't ever turn on the engine before checking X, even if you think it's okay" is "don't use C strcpy ever, even if you think you know it's correct there".

what is more important is that the lessons we learn need to be encapsulated and encoded into procedures that everyone can apply and learn from.

But in software, we can do better than that! We don't have to check a checklist ourselves if we can make a tool that makes it impossible to do the wrong thing (or rather, we don't have to have that thing on the checklist).

Some places do have checklists for software engineering, if not software. For example, a simplified process for deploying code might be: 1. Check that code compiles 2. Run test suite 3. Get code reviewed 4. Push to production And having such a list does help to ensure that code doesn't get pushed to production without being tested and reviewed. But it's better to use a system which automatically runs the tests and checks that it's been reviewed before the code goes into production (unfortunately the review itself can't be automated -- though parts of it can be, and that's useful too).

lots of things can go wrong in any language

Some languages, by design, exclude or drastically reduce certain classes of error.

Edit: I think I'm missing the point too. Proposing the perfect world as an engineering solution is silly. So in the context of "it's written in C", checklists would be a step forward.

And when we moved away from C for a lot of really important things, we saw memory issues and buffer overruns replaced by other trivial mistakes. In the late 90s, buffer overruns became a joke bug/security issue. In the late 00s we saw SQL injection (and similar injection attacks), XSS and other parser confusion tricks become the joke bug/security issue. Using python or ruby didn't magically fix these, and there are still fairly regular issues in using the libraries that enforce input and sanity checking. Heck those libraries still get big holes - there were a few active record issues not that long ago where the tool to sanitize data actually opened a hole! (Not to pick on any tool/framework - that one was just well publicized.)

I think the main point speaks more to the old saw "If you make something idiot proof, someone will just make a better idiot". Tools that automatically "fix old problems" are generally complicated an imperfect, and it becomes easy to accidentally trust the system to do the right thing on an edge case it doesn't handle. Having the automation of as many cases as possible is good, but having a full system to do in-depth knowledge preservation and issue capture is even better. The two things complement each other well.

Going back to the OP's original example/analogy - planes these days are full of automated systems, higher reliability parts, better interfaces, and all sorts of other improvements and failsafes so some errors from the past just can't happen. That doesn't mean they still don't do checklists and other manual checks to prevent the new issues from happening, nor have they abandoned some of the old basic checks, even if they "can't happen".

tl;dr - better tools are good, but they don't fix everything

Gerald Weinberg put it this way: when you solve the most important problem, you've promoted the second most important problem into first place.

That doesn't change that problem #1 was worthy to solve. The middle road is that we should neither rest on our laurels nor give up because of the impossibility of the perfect world.

With some discipline, it's possible to achieve the same level of security in C as in pretty much any other high-level language.

Some useful techniques: always strive for simplicity, use types to encapsulate data dependencies and enforce error checking (e.g. store the length and pointer of an array as part of a struct and use methods that perform bounds checks to modify or read from it -- granted, this style of programming can add overhead, but C is so fast to begin with that it rarely matters), don't use unsafe standard library functions, test rigorously, valgrind everything, use static code analysis tools.

Doing any of these things goes a long way to eliminate the vast majority of bugs specific to C, but unfortunately way too many C projects hardly do any of them. It can evidently be done, though, as there are some very robust C libraries out there.

See also djb's comments about qmail (http://cr.yp.to/qmail/guarantee.html).

The problem is that C requires positive effort, above the baseline, to have those guarantees.

Any system which relies on positive human effort is more likely to fail than a system which simply sets a higher baseline.

You can be safe on a motorbike if you are very careful, avoid dangerous conditions, drive more slowly than you want and practice extreme care around cars. You are still more likely to die. The baseline is simply lower and, when things do go wrong, you have less safety buffer than someone in a car.

But every OS is written in C.

Mainstream OS, yes. Muen (www.muen.sk) certainly isn't (for just one example, there are tons, some of them decades old, like Oberon)

Cool, interesting. I also like the top level domain.

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.