Not logged in
Log in now
Create an account
Subscribe to LWN
Pencil, Pencil, and Pencil
Dividing the Linux desktop
LWN.net Weekly Edition for June 13, 2013
A report from pgCon 2013
Little things that matter in language design
I rather prefer David Hanson's C Interfaces and Implementations.
Zeuthen: Writing a C library, part 1
Posted Jun 28, 2011 10:56 UTC (Tue) by dps (subscriber, #5725)
If you want to exit normally, even in an emergency, then you *should* be using exit(3) and not _exit(2) or abort(3). In the event of an assertion failure then clean up code could be destructive, and therefore should be avoided, but programs should not fail assertions.
IMHO a good program should handle all errors, including malloc failure, in a sane manner. It really is less painful that people that refuse to do it think. If you do *not* use a library then removing linked lists when something goes wrong is trivial.
Are you sure?
Posted Jun 28, 2011 20:17 UTC (Tue) by khim (subscriber, #9252)
IMHO a good program should handle all errors, including malloc failure, in a sane manner. It really is less painful that people that refuse to do it think.
What kind of handling are we talking about? xmalloc-style handling (which makes sense), "malloc masturbation" (where all calls to malloc are surrounded with explicit checks) or "really robust handling" (where you really handle all memory errors?)
First approach makes sense - I heartily reccomend it: early crash is great help with debugging. Third one is very hard while second one is utterly pointless and only uselessly adds thousands of lines of poorly tested code.
Why it's hard to handle out of memory errors properly? Well, modern systems include tons of ways to make you life miserable if you try to achieve this goal. Malloced "memory" comes uninitialized so even if malloc returned "success" actuall access may fail (think overcommit), and even if you'll fill all your allocated pages with something in your malloc wrapper it'll be not enough. Basically you must write your program in such a way a to handle SIGSEGVs everywhere - or all these checks you are so proud about are pointless. And it's not easy to support proper SIGSEGV handling if you program uses a lot of libraries and it not trivial itself.
Sadly I've seen so many libraries of type 2 and pitiful number of libraries of type 3 thus now my rule of thumb is: use xmalloc everywhere and compartmentalization a-la Chrome if you need some pretty out-of-memory UI.
Posted Jun 28, 2011 20:32 UTC (Tue) by nix (subscriber, #2304)
Yes, doing these checks makes it a bit more annoying to allocate memory, but not much. And the benefit is *definitely* worthwhile.
Posted Jun 28, 2011 23:33 UTC (Tue) by brouhaha (subscriber, #1698)
Alternatively, for platforms without backtrace() or equivalent, write your wrappers to accept additional arguments for the message to log for failure. If desired, you could use macros to make that a compile-time conditional, though I personally don't ever turn off any low-overhead debugging code.
Either approach seems far better than littering the source code with explict tests after each allocation. That just makes the code harder to read and maintain.
Posted Jun 29, 2011 10:59 UTC (Wed) by nix (subscriber, #2304)
Posted Jun 29, 2011 20:44 UTC (Wed) by brouhaha (subscriber, #1698)
I'm not thrilled with the name xmalloc(); I'd probably steal Perl's convention and call it malloc_or_die().
None of these approaches are well-suited to the original problem of doing memory management inside a library. The best practice I know of there is to pass in pointers to allocation/deallocation functions when the library is initialized, and make sure that any failures reported by those functions are handled appropriately. Appropriate means that if the library can't do anything sensible, it at least reports the allocation failure back to the caller.
When I use such a library, I might well pass in a malloc wrapper that prints a stack backtrace and exits.
Posted Jun 30, 2011 12:53 UTC (Thu) by nix (subscriber, #2304)
But saying "I won't bother, I'll just abort" is a disservice to your users, no matter *how* hard it is to handle OOM.
Posted Jun 30, 2011 6:19 UTC (Thu) by cpeterso (guest, #305)
> Your approach (the second one) would have worked, if I could have revamped the entire source base to use it. But it is rare that one gets the opportunity to do that, and malloc() tests at least don't look strange.
If you're brave, there's always the C preprocessor:
#define malloc(size) my_xmalloc_with_msg(size, __FILE__, __LINE__, __FUNCTION__)
This approach could still be useful if your macro was only #included by a subset of .c files, leaving some object code still calling libc's malloc().
Posted Jun 29, 2011 15:40 UTC (Wed) by dgm (subscriber, #49227)
In the context of your reply, I'm with you... most of the time. xmalloc() makes sense for most _programs_ (although not all of them). But, if we're discussing libraries (the subject of the article), then "really robust handling" is _the_ option.
Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds