Live data from Hacker News

How can C Programs be so Reliable? (2008)

tratt.net

51–60 of 230 posts

Re: How can C Programs be so Reliable? (2008)

#51
post #27

Earlier quoted context omitted.

"Discipline" is indeed the right word. I was taught C at Epitech. A single segfault, no matter insidious, was a valid reason to render a whole project NULL. We often had evaluations ran with LD_LIBRATY_PATH=malloc_that_fails.so or just piping /dev/urandom to stdin... Needless to say, calling exit() when a call to malloc() failed wasn't an acceptable recover routine.

I suspect you mean LD_PRELOAD=whatever.so

Thanks, haven't used it in two years and am a bit rusty :)

Re: How can C Programs be so Reliable? (2008)

#52

Tarsnap is the classic example of a C program whose reliability almost defies belief. Its codebase is large; it solves a very hard problem; and it manages to handle almost every cornercase flawlessly. (As of the latest version, it seems to handle every cornercase flawlessly, as far as I know.) But I've always wondered: if Colin were as experienced with Python as he is with C, would Tarsnap be better served by writing…

/x?fnid=KxPuWC6qnkl4nxcUTDh4xs resolves to "unknown or expired link". Do you have a full URL?

haha, exactly

Re: How can C Programs be so Reliable? (2008)

#53

"[Pointers are] arguably the trickiest concept in low-level languages, having no simple real-world analogy[.]" I'm not sure how "address" is not a good, "simple real-world analogy" for pointers. It may be that I've just internalized enough of the behavior of pointers that I'm glossing over important differences, though... I struggled with pointers long enough ago that I don't remember struggling with pointers.

For a lot of people I think it takes a while to really internalize the ramification of the fact that you can have a pointer to memory you're not allowed to use. (That, plus the way they're used in C as a cheap answer to templates/generics.) I understood that a pointer was an address from the start, but it was still some time before I figured out how to use them correctly.

C implements a fairly low-level but general model of how a computer works, and a programmer's understanding of pointers is something of a proxy for their understanding of how that model works. Therefore, C has a sort of built-in test for a level of competence in a programmer. Unfortunately, it is by no means perfect, and you can still find people writing in C who have no idea why they should not return a pointer to an automatic variable.

Re: How can C Programs be so Reliable? (2008)

#54
post #8

Tarsnap is the classic example of a C program whose reliability almost defies belief. Its codebase is large; it solves a very hard problem; and it manages to handle almost every cornercase flawlessly. (As of the latest version, it seems to handle every cornercase flawlessly, as far as I know.) But I've always wondered: if Colin were as experienced with Python as he is with C, would Tarsnap be better served by writing…

Wait, HN is good? The community is interesting, but I've never been particularly impressed by the implementation. In particular, the "feature" where "More" links and such randomly expire after a while just screams "shoddy implementation" to me.

The UI is in some way (i think) intentionally poor. For example, when you want to reply to a comment it takes you to a new page, and then you still have to click on the textarea to focus it. I think they don't want people to be able to comment quickly.

Re: How can C Programs be so Reliable? (2008)

#55
post #26

Earlier quoted context omitted.

> Needless to say, calling exit() when a call to malloc() failed wasn't an acceptable recover routine. What do you do when malloc fails? A bit of graceful shutdown and logging seems like it would be in order, but otherwise how do you keep rolling if mallocs start failing? It seems to me like that would indicate something has gone unusually wrong and full recovery is futile.

I don't get the sense that there was any attempt to recover from errors - it sounds more like they were enforcing that error checking occurred, by replacing `malloc` with one that just returned `NULL` always. It sounds like the goal was to make sure that one didn't assume `malloc` would always succeed and just use the memory. Indeed, recovery is basically futile in this case and your program is going to shut down pre…

Like eliteraspberrie said, the proper way to recover from an error is to unroll your stack back to your main function and return 1 there.

Error checking was enforced for EVERY syscall, be it malloc() or open(). Checking for errors was indeed required but not enough: proper and graceful shut down was required too.

Re: How can C Programs be so Reliable? (2008)

#56

The author's point is weakened by the fact that the Converge VM is now (5 years after this article) written in python: https://github.com/ltratt/converge/search?l=c (as of https://github.com/ltratt/converge/tree/08dadda29b/vm ). Compare https://github.com/ltratt/converge/tree/converge-1.x/vm . "there are some obvious reasons as to why it might be so reliable: it's used by (relatively) large numbers of people, who hel…

I believe he explains this switch here: http://tratt.net/laurie/blog/entries/fast_enough_vms_in_fast...

It's a very good read. IIRC, the reasons aren't really rooted in the language that is used. It's more about the tooling provided by PyPy for constructing a compiler.

Re: How can C Programs be so Reliable? (2008)

#57
post #19

Earlier quoted context omitted.

It depends on the problem you're trying to solve, I think. Let's consider a command line application that fetches a URL, like wget. Without exceptions, you would check the return code of all the system functions you call (dns, sockets, etc), and if any of them fail you can't really recover. You just write out an error message and exit. With exceptions, you could wrap the whole thing and if any system function throws…

But what if the exception was in your code and not the system call? This is incredibly dangerous. Monads are perfect for this. Really combines the best of both worlds without all the unspecified/undefined behavior.

Then it should be a different exception, and if it matters, you should be treating that class of exceptions differently. Sometimes it doesn't matter.

Re: How can C Programs be so Reliable? (2008)

#58
post #43

Earlier quoted context omitted.

The most common way to indicate that an error has occurred in a C function is to return non-zero. If this is done consistently, and return values are always checked, an error condition will eventually make its way up to main, where you can fail gracefully. For example: int a(void) { ... if (oops) { return 1; } return 0; } int b(void) { if (a(...) != 0) { return 1; } return 0; } int main(void) { if (b(...) != 0) { exi…

What's the point of propagating all errors way up to main if you're only going to exit anyway? I think we know how to indicate errors in C functions. What to do about specific errors, in this case allocation failures, is a more interesting question.

To make sure you free() all your previous allocations on the way down. You can choose not too, it's "kinda" the same (can't remember the exact difference) but it's dirty and people with OCD just won't accept it.

(Disclosure: I got OCD too, this is not meant to make C development hostile to people with OCD.)

Re: How can C Programs be so Reliable? (2008)

#59
post #26

Earlier quoted context omitted.

"Discipline" is indeed the right word. I was taught C at Epitech. A single segfault, no matter insidious, was a valid reason to render a whole project NULL. We often had evaluations ran with LD_LIBRATY_PATH=malloc_that_fails.so or just piping /dev/urandom to stdin... Needless to say, calling exit() when a call to malloc() failed wasn't an acceptable recover routine.

> Needless to say, calling exit() when a call to malloc() failed wasn't an acceptable recover routine. What do you do when malloc fails? A bit of graceful shutdown and logging seems like it would be in order, but otherwise how do you keep rolling if mallocs start failing? It seems to me like that would indicate something has gone unusually wrong and full recovery is futile.

Go ahead. Call exit(). On your HTTP/IRC/anything server. Just because you couldn't allocate memory for one more client. Now your service is down and the CTO is looking for blood =)

Yes, it's far-fetched and like some said further down the comments, you "can't" run out of memory in Linux, but straight killing a service is never good.

Re: How can C Programs be so Reliable? (2008)

#60
post #43

Earlier quoted context omitted.

The most common way to indicate that an error has occurred in a C function is to return non-zero. If this is done consistently, and return values are always checked, an error condition will eventually make its way up to main, where you can fail gracefully. For example: int a(void) { ... if (oops) { return 1; } return 0; } int b(void) { if (a(...) != 0) { return 1; } return 0; } int main(void) { if (b(...) != 0) { exi…

What's the point of propagating all errors way up to main if you're only going to exit anyway? I think we know how to indicate errors in C functions. What to do about specific errors, in this case allocation failures, is a more interesting question.

If malloc() fails now, it might succeed again later. So you can just go on doing everything else you were doing, then try the memory-hungry operation again in the future.

For example, this could be important in systems where you might be controlling physical hardware at the same time as reading commands from a network. It's probably a good idea to maintain control of the hardware even if you don't have enough memory right now to read network commands.

Post reply on HN