Are you sure?
Are you sure?
Posted Jun 28, 2011 20:17 UTC (Tue) by khim (subscriber, #9252)In reply to: Zeuthen: Writing a C library, part 1 by dps
Parent article: Zeuthen: Writing a C library, part 1
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)
[Link] (5 responses)
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)
[Link] (4 responses)
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)
[Link] (3 responses)
Posted Jun 29, 2011 20:44 UTC (Wed)
by brouhaha (subscriber, #1698)
[Link] (1 responses)
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)
[Link]
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)
[Link]
If you're brave, there's always the C preprocessor:
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
Posted Jun 29, 2011 15:40 UTC (Wed)
by dgm (subscriber, #49227)
[Link]
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.
Are you sure?
Are you sure?
Are you sure?
Are you sure?
Are you sure?
Are you sure?
> 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.
#define malloc(size) my_xmalloc_with_msg(size, __FILE__, __LINE__, __FUNCTION__)
malloc()
.
Are you sure?
> 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?)