On Jan 31, 9:24 am, Keith Thompson <ks...@mib.orgw rote:
"Bartc" <b...@freeuk.co mwrites:
"CBFalconer " <cbfalco...@yah oo.comwrote in message
news:47******** *******@yahoo.c om...
Stan Milam wrote:
jacob navia wrote:
>>1: It is not possible to check EVERY malloc result within
complex software.
>I disagree. It is possible. You just have to decide you want to
sweat the details bad enough and do the hard work.
What hard work? For example:
if (!(p = malloc(N * sizeof *p))) fixitup(&p, N * sizeof *p);
if (!p) exit(EXIT_FAILU RE);
Hmm, perhaps not quite as eloquent as:
p=heap(N);
Then you can get on with the next thing. Of course this is a made-up
language, but this form clearly has some attraction and I think trying to
achieve something similar in C was the aim of this and the xmalloc thread.
Changing the syntax for memory allocation doesn't magically solve
anything.
(I keep seeing this form, usually as 'new', in other languages; what do
/they/ do when out-of-memory?)
It varies from language to language. Typically either the allocator
returns a null pointer on failure (exactly what C's malloc() does), or
it throws/raises an exception (if the language supports exceptions).
It's *always* possible for an attempted memory allocation to fail.
The possible ways to handle this possibility are:
1. Ignore it and keep going (dangerous).
This is not a solution.
2. Use an allocator that immediately aborts the program on failure.
You only do this because you don't know how to solve the problem
without all that memory, or else, you *can't* solve the problem
without all that memory (rare.)
3. Check for failure on each allocation. On failure:
3a. Immediately abort the program (equivalent to 2).
3b. Clean up and abort the program.
3c. Clean up and continue processing (this can be difficult, but
it's important if you want the program to be robust).
3a = 3b = 2. Aborting doesn't require that you clean up first -- any
real OS(TM) will clean you up upon aborting anyways.
Your 3c only makes sense if you are talking about your whole program,
not just the code fragments where the error occurs (because that
typically will make no sense.) But you are inherently omitting how
you *achieve* it. In straight C you do it by observing the following
in your primitive calls:
3c1) Undo all operations in your scope and return from the current
function with an error code (my typical approach is NULL for pointers
and negative numbers for status codes).
which is applied recursively throughout your "primitives " call chain.
And in your policy/management calls:
3c2) If a strategy fails, go to the next strategy until all are
exhausted, then if everything fails log or return an error code that
amounts to "INCOMPLETE DUE TO LACK OR RESOURCES".
Of course this means you have to understand the distinction between
primitive calls and policy/management calls in your program.
Primitives make and handle data structures, whereas policy performs
actions on these data structures.
4. If the language supports exceptions (C doesn't), catch the error at
whatever level is appropriate, not necessarily immediately after
the attempted allocation. Perform appropriate cleanup and recovery
in the exception handler.
This is just a fancy way of implementing 3c with special language
features.
Going back to "at those lines of code" programming solutions I would
add:
5. Defer the error (but retain this information) until it can be
handled in an aggregated way.
6. Provide a stand-in for typical functionality. (I.e., return some
static memory declaration.) This can only be done in rare instances
where contention is a less serious issue than running out of memory,
or if you can guard the memory location with a semaphore, for example.
--
Paul Hsieh
http://www.pobox.com/~qed/ http://bstring.sf.net/