Earlier quoted context omitted.
I don't think you understand proper exception handling. Catching and wrapping DiskFullException is pretty pointless because what are you going to do about it? Nothing. It's nonsensical for a preferences class to deal with that situation. Instead let it bubble up and so that the caller has the option of handling it, for example by showing a dialog "Delete temporary files and try again?" You'll never be able to catch a…
You state a lot of half truths ("you'll never be able to catch all exceptions"), don't justify the assumptions and didn't handle the core of my argument (abstraction leakage). In the hurry to insult me, did you actually read my argument?
How can C Programs be so Reliable? (2008)
181–190 of 230 posts
Re: How can C Programs be so Reliable? (2008)
#182Popular C software is so reliable because of enormous amount of effort spent developing, testing, and polishing it over many years - not because error handling in C is superior to that in higher-level languages. If your python script sticks around for 30 years constantly being used by millions of people - I bet it will be rock solid as well. All other things [1] being equal [2], a program written in a higher-level la…
Re: How can C Programs be so Reliable? (2008)
#183Earlier quoted context omitted.
If your program is going to exit anyway, there's no need to call free() on allocated memory. The operating system will reclaim all of the memory it granted to your process when it exits. Remember that malloc lives in your process , not the kernel. When you ask for memory from malloc, it is actually doling out memory that you already own - the operating system granted it to you, when malloc requested it. And malloc re…
Multiple reasons. Some kernels may not get memory back by themselves and expect each application to give it back. We're lucky that the kernels we use everyday do, but we may one day have to write for a target OS where it's not the case. Just hoping "the kernel will save us" is a practice as bad as relying on undefined behaviors. If you're coding correctly, you have exactly as much malloc()'s as you have free()'s, so…
Second, please re-read my last sentence. I specifically addressed things that the kernel does not reclaim. This would also include System V shared memory segments and the like. You must manage these yourself, and it is always messy. Typically, rather than calling exit directly, you're going to invoke a routine that knows about all such resources, frees them, then calls exit. But you still don't need to unwind your stack back to main.
Third, the kernel always gets back all of its memory that was granted through conventional means. That's what operating systems do. I think you have a fundamental misunderstanding of what malloc is, and where it lives. Malloc is a user-level routine that lives inside of your process. When you call malloc, it is granting you memory that you already own. Malloc is just a convenience routine that sits between you and the operating system. When you say malloc(4), it does not go off and request 4 bytes from the operating system. It looks into large chunks of memory the operating system granted to it, and gives you some, updating its data structures along the way. If all of its chunks of memory are currently allocated, then it will go ask the operating system for memory - on a Unix machine, typically through a call to brk to mmap. But when it calls brk or mmap, it will request a large amount of memory, say a few megabytes. Then, from that large chunk, it will carve out 4 bytes for you to use.
(This is why off-by-one errors are so pernicious in C: the chances are very good that you actually do own that memory, so the kernel will happily allow you to access the value.)
Now, even if you are a good citizen and return all memory to malloc, the operating system still has to reclaim tons of memory from you. Which memory? Well, your stacks and such, but also all of that memory that malloc still controls. When you free memory back to malloc, malloc is very unlikely to then give it back to the operating system. So all programs, at exit, will have memory that they own that the kernel will need to reclaim.
Re: How can C Programs be so Reliable? (2008)
#184Earlier quoted context omitted.
One advantage of forking servers; kill and reboot the parent, and you don't loose in-flight connections. That said, I do this as well, even the best behaved daemon can get... funky... after a few months. Planned outages for a daemon restart are ok in my experience, particularly if you can fail over to other nodes as part of a rolling restart. Of course, this refers to planned restarts, though forking servers helps wi…
Don't you find performance suffers? AIUI this approach means you can only handle as many concurrent requests as you have processes, and the OS scheduler has less information to work with than if you were using threads.
Re: How can C Programs be so Reliable? (2008)
#185"[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.
I think pointer syntax in C, not pointers themselves, is what causes confusion for most beginner programmers. This post explains it well: http://objcsharp.wordpress.com/2013/08/14/the-great-pointer-...
Re: How can C Programs be so Reliable? (2008)
#186Earlier quoted context omitted.
Your experience with languages with exceptions seem to come from people who misuse them. Randomly placing catch clauses around in the code is not good practice, even if perhaps a majority of all programmers in safe languages code that way. That causes latent bugs that are incredibly hard to debug. The trick is to almost never ever catch exceptions. For example, in his post he describes a bug caused by accessing beyon…
> The trick is to almost never ever catch exceptions. I strongly disagree. Not catching exceptions leaks abstraction layers. If I have a Prefs::save() method, I don't want it throwing a DiskFullException when the Prefs class is an abstraction of a preferences datastore. I don't care what is the final store, as long as it fits the abstraction. A well designed abstraction will catch and wrap the exception into somethin…
Re: How can C Programs be so Reliable? (2008)
#187Earlier quoted context omitted.
Don't you find performance suffers? AIUI this approach means you can only handle as many concurrent requests as you have processes, and the OS scheduler has less information to work with than if you were using threads.
Not typically: using forking daemons does not mean that you can't also use threads. The ideal model probably uses both - so they can be stuck to a processor, but still use threads per request. It's nice to have a library to abstract the implementation details away for you, but not necessary.
Re: How can C Programs be so Reliable? (2008)
#188Earlier quoted context omitted.
Type safety is a lie. Everything is a piece of memory. C does not hide this from you, it's a design feature and not a bug.
> Type safety is a lie. Everything is a piece of memory. So speaks an Assembly developer > C does not hide this from you, it's a design feature and not a bug. I guess the design goal was to make security exploits as easy as taking caddies from children.
C is a portable, readable assembler abstraction in a lot of ways, yes. I'm not seeing what's wrong with that. Was that supposed to be an insult?
>> I guess the design goal was to make security exploits as easy as taking caddies from children.
Do children often have caddies? I've never noticed a child with a caddy. Golfers perhaps.
I'm still not sure why you think type safety is the be-all and end-all of everything. You can have memory violations and leaks just as easily in type-safe environments as any other. There are lots of ways to f*ck up in C, but the flexibility turns out to be useful as well, when used appropriately.
Re: How can C Programs be so Reliable? (2008)
#189Earlier quoted context omitted.
Exactly. Writing libraries in C means you have to be much more strict than simple throwaway single execution binaries. What our company has ended up doing is wrappering most low level functions with the common code around it. For example, fopen() may fail and return EINTR if the process received a signal just as it was opening a file (we use signals to tell processes to reread their config so this does happen albeit…
> Also code where you have to undo all of the work already done in the function up until that point, which can get a little tedious, i.e.:- Sorry pal, you're doing it wrong. At least, this is not the way I've done it and seen it done in large C code bases. You're supposed to have only one return statement, and one block that frees everything. For example if you initialize `foo`, `bar`, and `qux` to `NULL`. Then testi…
You can nest under if(thing!=NULL) but then you end up with indentation creep.
You can use the goto pattern if you like but some folks will tell you that goto's are never, ever to be used.
Or you can do what's done above. When it comes down to it the logic is basically identical and it's just down to code formatting.
Re: How can C Programs be so Reliable? (2008)
#190Popular C software is so reliable because of enormous amount of effort spent developing, testing, and polishing it over many years - not because error handling in C is superior to that in higher-level languages. If your python script sticks around for 30 years constantly being used by millions of people - I bet it will be rock solid as well. All other things [1] being equal [2], a program written in a higher-level la…
Exceptions are kind of like gotos, but worse, because the jump target is decided at runtime based on the state of the call stack and therefore cannot be determined just by looking at the code. So they're more like comefroms [0] than gotos. [0] http://en.wikipedia.org/wiki/COMEFROM