Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

xmalloc string functions

42 views
Skip to first unread message

Malcolm McLean

unread,
Jan 27, 2008, 9:57:02 AM1/27/08
to
Here are six functions implemented on top of xmalloc(). No C programmer
should have any triouble providing the implemetations, though replace and
getquote are non-trivial.

char *dup(const char *str);
char *cat(const char *str1, const char *str2);
char *catandkill(char *str1, const char *str2);
char *tok(const char *str, const char *delims, char **end);
char *midstr(const char *str, int idx, int len);
char *replace(const char *str, const char *pattern, const char *rep);
char *getquote(const char *str, char quote, char escape, char **end);
char *getline(FILE *fp);

All return strings allocated with xmalloc().

dup() is strdup(), and duplicates a string. cat() concatenates two strings.
catandkill concatenagtes two strings, and frees the first. It also returns
dup(str2) is the first pointer is null. It is designed for building strings
in conveneint loops.
tok() is strtok() that takes a string argument instead of using a global.
midstr() takes out a central portion of the string. replace() is a find and
replace, getquote() retrives the next quoted string, allowing for the quotes
themselves to be escaped. You will have to escape non-quote escaped
characters manually, of course. getline() will be a familiar friend.

I've think we've got something quite powerful here, purely because none of
these functions can ever return null for out of memory conditions. It
massively simplifies string handling.
The library is not terribly efficient and doesn't pretend to be. If you are
doing heavy string processing you might want to look at Paul Hsieh's better
string library, that stores a length parameter with strings. It is meant to
be a few simple functions for easy manipulation.
--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

santosh

unread,
Jan 27, 2008, 10:24:43 AM1/27/08
to
Malcolm McLean wrote:

Just one suggestion. Usually it's not typical for a /library/ function
to take the liberty of terminating your program. I suggest that
xmalloc() calls a user supplied call-back function if malloc() fails.
The address of the call back need not be passed with every function in
the library. Instead the user could call a call-back register function
before using the other library routines.

The call-back allows the library client to decide the strategy to adopt
on malloc() failure. The client might decide to just call exit() or it
might print a few messages before doing so, or it might decide to
continue with some other part of the program, or whatever...

Eric Sosman

unread,
Jan 27, 2008, 10:24:59 AM1/27/08
to
Malcolm McLean wrote:
> Here are six functions implemented on top of xmalloc(). No C programmer
> should have any triouble providing the implemetations, though replace
> and getquote are non-trivial.
>
> char *dup(const char *str);
> char *cat(const char *str1, const char *str2);
> char *catandkill(char *str1, const char *str2);
> char *tok(const char *str, const char *delims, char **end);
> char *midstr(const char *str, int idx, int len);
> char *replace(const char *str, const char *pattern, const char *rep);
> char *getquote(const char *str, char quote, char escape, char **end);
> char *getline(FILE *fp);
>
> All return strings allocated with xmalloc().
>
> dup() is strdup(), and duplicates a string. cat() concatenates two
> strings. catandkill concatenagtes two strings, and frees the first. It
> also returns dup(str2) is the first pointer is null. It is designed for
> building strings in conveneint loops.
> tok() is strtok() that takes a string argument instead of using a
> global. midstr() takes out a central portion of the string. replace() is
> a find and replace, getquote() retrives the next quoted string, allowing
> for the quotes themselves to be escaped. You will have to escape
> non-quote escaped characters manually, of course. getline() will be a
> familiar friend.

The specifications are too weak to drive implementations.
What does xmalloc() do when unable to allocate memory? Does
replace() replace all occurrences, or just the first, or just
the last, or what? What does getquote() do with unbalanced
quotes? Does getline() keep or discard the '\n', and what does
it do on an I/O error? (See the recent thread on design of line-
input functions to see how divergent people's opinions are on
how this "familiar friend" should behave.)

> I've think we've got something quite powerful here, purely because none
> of these functions can ever return null for out of memory conditions. It
> massively simplifies string handling.

... and massively complicates error handling. If xmalloc()
can unilaterally terminate the program, the whole suite is
unusable except in toy programs. If there's a fancier framework,
all functions that use the suite or that call other functions
that might use the suite need to be plugged in to the framework.

Design consists of more than writing a few declarations.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Malcolm McLean

unread,
Jan 27, 2008, 10:42:58 AM1/27/08
to

"santosh" <santo...@gmail.com> wrote in message

> Just one suggestion. Usually it's not typical for a /library/ function
> to take the liberty of terminating your program. I suggest that
> xmalloc() calls a user supplied call-back function if malloc() fails.
> The address of the call back need not be passed with every function in
> the library. Instead the user could call a call-back register function
> before using the other library routines.
>
That's exactly how xmalloc() works. Except that the user callback can never
say "return null". User must either supply some memory or terminate the
program. He can of course ask the end user to close down other programs, and
ha can conduct an emergency save/backup.

vipp...@gmail.com

unread,
Jan 27, 2008, 1:43:17 PM1/27/08
to
On Jan 27, 5:42 pm, "Malcolm McLean" <regniz...@btinternet.com> wrote:
> "santosh" <santosh....@gmail.com> wrote in message

> > Just one suggestion. Usually it's not typical for a /library/ function
> > to take the liberty of terminating your program. I suggest that
> > xmalloc() calls a user supplied call-back function if malloc() fails.
> > The address of the call back need not be passed with every function in
> > the library. Instead the user could call a call-back register function
> > before using the other library routines.
>
> That's exactly how xmalloc() works. Except that the user callback can never
> say "return null". User must either supply some memory or terminate the
> program. He can of course ask the end user to close down other programs, and
> ha can conduct an emergency save/backup.
And you consider that powerful mr Malcom McLean?
That right there is very weak and a very bad practise.
Example:

-- snip.c --
/* no headers, we are using imaginary functions anyway */

int main(void) {

FILE *fp = fopen("/dev/zero", "r"); /* assume UNIX & fopen doesn't
fail */
char *foo, *bar;
foo = dup("Hello, World"); /* assume success */
bar = getline(fp); /* obviously this will fail to allocate enough
memory, will quit and a memory leak will occur because the return
value of dup() was not freed */
free(bar); free(foo);
return 0;
}
-- snip.c --

I can think of a *lot* more reasons why I would not want my program to
terminate because an allocation failed.
These solutions are horrible, I strongly suggest that you avoid using
them in your own programs.

Kelsey Bjarnason

unread,
Jan 27, 2008, 6:38:35 AM1/27/08
to
[snips]

On Sun, 27 Jan 2008 15:42:58 +0000, Malcolm McLean wrote:

> That's exactly how xmalloc() works. Except that the user callback can
> never say "return null". User must either supply some memory or
> terminate the program.

So the user - in this case, the coder using your function - has
absolutely no option to do something as basic as reducing the memory
allocation request and trying again, or scheduling the operation for
later processing and continuing on to some other action.

Yeah, useful, that. Totally aside from the fact it lies about what it
does, then actually fails to even meet the functionality stated in the
lie.

Kelsey Bjarnason

unread,
Jan 27, 2008, 6:48:05 AM1/27/08
to
[snips]

On Sun, 27 Jan 2008 10:24:59 -0500, Eric Sosman wrote:

> The specifications are too weak to drive implementations.
> What does xmalloc() do when unable to allocate memory?

Calls an optionally-user-specified function to figure out how to free up
some memory (eg opening a window to say "Please close another
application", which, of course, assumes there's enough memory to do so),
or, failing that, aborts the application.

Yes, that's right, it's a trap door function: you can enter, but you can
never leave, unless and until the memory is available. No error
reporting, no recovery, no options at all. That is the intent of the
code, as Malcolm has expressed more than once, that you *cannot* recover
from any allocation failure. You get the memory, or you exit. Period.

> Does replace()
> replace all occurrences, or just the first, or just the last, or what?
> What does getquote() do with unbalanced quotes?

And does it do single quotes? Double quotes? Both?

>> I've think we've got something quite powerful here, purely because none
>> of these functions can ever return null for out of memory conditions.
>> It massively simplifies string handling.
>
> ... and massively complicates error handling.

No, no, it makes error handling *easier*, because you don't ever need to
*do* error handling. xmalloc does that for you - by ensuring you get the
memory, or the app aborts. See how wonderful it is? No need for all
that error handling code at the calling point. Also no way to ever do
anything like, oh, reduce the allocation request and try again, or
reschedule the operation for later, etc, etc, etc, but hey, it's not like
any application would ever actually do things like that.

> If xmalloc()
> can unilaterally terminate the program

Not "can", by design it is *required to*, unless the allocation
succeeds. One or the other: you get the memory, or the app dies.

> the whole suite is unusable
> except in toy programs.

Except it's of little use in toy apps. Such an app probably doesn't do a
hell of a lot of complex allocations in the first place, so wouldn't
benefit significantly from "easy malloc". A complex app where there may
be thousands or millions of allocations done from hundreds or thousands
of places in the code, now this would benefit from "easy malloc" - if it
were actually useful.

The xmalloc notion presented is of little interest in a toy app, and is
unusable in a real app. One wonders where, exactly, it would actually be
used. One place it won't be used: my code. I actually like to be able
to choose a course of action on allocation failure, not be stuck with
some asinine notion that allocation will succeed or there's no point in
continuing.

Ian Collins

unread,
Jan 27, 2008, 2:52:08 PM1/27/08
to
Kelsey Bjarnason wrote:
> [snips]
>
> On Sun, 27 Jan 2008 15:42:58 +0000, Malcolm McLean wrote:
>
>> That's exactly how xmalloc() works. Except that the user callback can
>> never say "return null". User must either supply some memory or
>> terminate the program.
>
> So the user - in this case, the coder using your function - has
> absolutely no option to do something as basic as reducing the memory
> allocation request and trying again, or scheduling the operation for
> later processing and continuing on to some other action.
>
Doesn't that meet the requirements for "supply some memory"? That
requirement appears sufficiently vague to cover just about anything!

--
Ian Collins.

Yevgen Muntyan

unread,
Jan 27, 2008, 3:34:58 PM1/27/08
to
Malcolm McLean wrote:
> Here are six functions implemented on top of xmalloc(). No C programmer
> should have any triouble providing the implemetations, though replace
> and getquote are non-trivial.

[snip]

> I've think we've got something quite powerful here, purely because none
> of these functions can ever return null for out of memory conditions. It
> massively simplifies string handling.

Take a look at glib,
http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html

Best regards,
Yevgen

Malcolm McLean

unread,
Jan 27, 2008, 3:59:04 PM1/27/08
to

"Ian Collins" <ian-...@hotmail.com> wrote in message
Rescheduling would be possible. Reducing the amount allocated not, because
then caller would have to fall back on some alternative algorithm. That
tends not to make sense except in special situations, where malloc() is the
appropriate call.

Malcolm McLean

unread,
Jan 27, 2008, 4:07:38 PM1/27/08
to

"Kelsey Bjarnason" <kbjar...@gmail.com> wrote in message

> Yes, that's right, it's a trap door function: you can enter, but you can
> never leave, unless and until the memory is available. No error
> reporting, no recovery, no options at all. That is the intent of the
> code, as Malcolm has expressed more than once, that you *cannot*
> recover from any allocation failure. You get the memory, or you exit.
> Period.
>
Exactly. Which is what these string functions will do. They will never
return null for out of memory conditions.
>
> And does it do single quotes? Double quotes? Both?
>
The quote character is passed, together with the character to escape the
quotes (which can be the quote itself). It doesn't support different opening
and closing quotes, which maybe it ought.

> No, no, it makes error handling *easier*, because you don't ever need to
> *do* error handling. xmalloc does that for you - by ensuring you get the
> memory, or the app aborts. See how wonderful it is? No need for all
> that error handling code at the calling point. Also no way to ever do
> anything like, oh, reduce the allocation request and try again, or
> reschedule the operation for later, etc, etc, etc, but hey, it's not like
> any application would ever actually do things like that.
>

You've got it. If machine won't give us a hundred bytes, and the end user
cannot free up any more applications, what can we do, seriously? The
ambitious might attempt an emergency save in the callback function/


>
> Except it's of little use in toy apps. Such an app probably doesn't do a
> hell of a lot of complex allocations in the first place, so wouldn't
> benefit significantly from "easy malloc". A complex app where there may
> be thousands or millions of allocations done from hundreds or thousands
> of places in the code, now this would benefit from "easy malloc" - if it
> were actually useful.
>
> The xmalloc notion presented is of little interest in a toy app, and is
> unusable in a real app. One wonders where, exactly, it would actually be
> used. One place it won't be used: my code. I actually like to be able
> to choose a course of action on allocation failure, not be stuck with
> some asinine notion that allocation will succeed or there's no point in
> continuing.
>

Single user apps. Or database apps where there isn't a robust memory
recovery strategy in place - e.g. anything which uses an X server. Not for
an app where it doesn;t matter if you crash or not on the null pointer
dereference that will follow a failed, unchecked malloc(), not for an app
which absolutely must not terminate but can abort jobs if memory gets low.
Between that low end and high end there's an enormous number of programs.

William Ahern

unread,
Jan 27, 2008, 5:12:01 PM1/27/08
to

> [snip]

glib is where bad ideas go to die. Now, if somebody just had the nerve to
tell them....

Yevgen Muntyan

unread,
Jan 27, 2008, 5:38:25 PM1/27/08
to

There are at least two desktop environments built on glib, and
bunch of independent applications, and they actually work. Have
you got something more substantial than "bad ideas"?

Best regards,
Yevgen

William Ahern

unread,
Jan 27, 2008, 5:55:32 PM1/27/08
to

I only brought it up because glib uses an xmalloc() wrapper which dies on
allocation failure, and Evolution and similar glib-based applications loved
to crash when, for instance, I would [try to] open a message with an
especially long marked-up diff. Of course, it was worse (as in more
frequent) before I disabled the Linux OOM killer. Never infrequent enough,
however.

In my experience, glib-based applications "mostly" work. Not sure whether
that has more to do w/ the xmalloc() wrapper, or other issues. I'll grant
you that the organization and design of glib source interfaces is... a
matter of taste.

One of my rules of thumb is that if a network daemon uses glib, I
automatically exclude it from consideration. I can deal when an application
crashes and destroys my work. I don't want to be responsible for installing
an application which crashes and destroys or interrupts _other_ people's
work.

Randy Howard

unread,
Jan 27, 2008, 6:10:12 PM1/27/08
to
On Sun, 27 Jan 2008 16:12:01 -0600, William Ahern wrote
(in article <h6cv65-...@wilbur.25thandClement.com>):

:)

You gdon't glike ghaving gall gyour gvariables gprexfed gwith g?

--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Kelsey Bjarnason

unread,
Jan 27, 2008, 10:32:45 AM1/27/08
to
[snips]

On Sun, 27 Jan 2008 21:07:38 +0000, Malcolm McLean wrote:

>> recover from any allocation failure. You get the memory, or you exit.
>> Period.
>>
> Exactly. Which is what these string functions will do. They will never
> return null for out of memory conditions.

Rendering them instantly useless for any real-world code. You know, code
where something as trivial as an allocation failure does *not*
necessarily imply a requirement to abort, code where if an allocation
fails and is detected, can be dealt with any number of ways, up to and
including shrinking another allocated region to free up space so the new
allocation can succeed.

>> And does it do single quotes? Double quotes? Both?
>>
> The quote character is passed,

So if I have both single and double quotes included, it doesn't work?
Not terribly useful, particularly in a function whose sole purpose is to
get quotes.

>> No, no, it makes error handling *easier*, because you don't ever need
>> to *do* error handling. xmalloc does that for you - by ensuring you
>> get the memory, or the app aborts. See how wonderful it is? No need
>> for all that error handling code at the calling point. Also no way to
>> ever do anything like, oh, reduce the allocation request and try again,
>> or reschedule the operation for later, etc, etc, etc, but hey, it's not
>> like any application would ever actually do things like that.
>>
> You've got it. If machine won't give us a hundred bytes

100 bytes? Excuse? Where did you get the asinine notion that a call to
malloc is limited to 100 bytes? Last I checked, it was limited to
SIZE_MAX, which with the tools I use is either 4294967295 bytes or
18446744073709551615 bytes depending on whether you're running a 32-bit
or a 64-bit OS. Hell, even on a 16-bit machine, you can generally
allocate up to 64K. 100 bytes? Where did that bit of nonsense come from?


>, and the end
> user cannot free up any more applications, what can we do, seriously?

All *sorts* of things, unless he uses your code in which case he's
screwed.

>> The xmalloc notion presented is of little interest in a toy app, and is
>> unusable in a real app. One wonders where, exactly, it would actually
>> be used. One place it won't be used: my code. I actually like to be
>> able to choose a course of action on allocation failure, not be stuck
>> with some asinine notion that allocation will succeed or there's no
>> point in continuing.

> Single user apps.

You mean like, oh, a word processor which might not have enough resources
available to run the spell checking module, but which has *absolutely no
justification* for realizing it can't allocate the memory, choosing to
die a graceless death, taking your entire document with it?

No freaking thank you. That sort of idiocy went out with... er... no,
actually, I've been coding for 29 years now and I can't recall a time it
was *ever* an acceptable practise.

> Or database apps where there isn't a robust memory
> recovery strategy in place

Ah, right, so if it can't allocate enough memory to process that large
select you just issued, it makes perfect sense to crash and die, taking
with it any unstored data, rather than report back that there's
insufficient memory. Yeah, well, not like *data* matters, not in a
*database* app.

>- e.g. anything which uses an X server.

WTF does an X server have to do with a database?

You persist in demonstrating you have no concept at all how to design
software.

Yevgen Muntyan

unread,
Jan 27, 2008, 6:48:15 PM1/27/08
to

I'd think evolution crashed because it crashed. You can look at
its list of bugs to see what I mean. If it was abort() inside
g_malloc(), then it probably leaked so much that it indeed has
eaten everything and asked for more. In which case you can't
really blame glib ;)
(Here I'd be actually grateful if such applications were killed
immediately, because they first freeze X, and I've got to wait
for ten minutes to switch to console and kill the application.
They just don't die themselves.)

>
> In my experience, glib-based applications "mostly" work. Not sure whether
> that has more to do w/ the xmalloc() wrapper, or other issues.

There is no xmalloc() wrapper in glib. Anyway, have you never
seen "mostly working" application which do not use glib? Bugs
are everywhere, on all platforms. Do you have a real base for
saying that g_malloc() is somehow responsible for crashes you
have seen? Something other than "evolution crashed", that is,
or "similar applications" (similar glib-based applications
which open messages, huh?).

You know, I have heard things like you are saying only from
people who talk about xmalloc() and related things. Never from
users. Why is that? Perhaps because buggy applications are
buggy applications, not some poor creatures crashing because
glib memory handling is broken?

> I'll grant
> you that the organization and design of glib source interfaces is... a
> matter of taste.

Yes it is, certainly. And it's irrelevant.

>
> One of my rules of thumb is that if a network daemon uses glib, I
> automatically exclude it from consideration. I can deal when an application
> crashes and destroys my work. I don't want to be responsible for installing
> an application which crashes and destroys or interrupts _other_ people's
> work.

It's fine, nobody promiced glib will work for any program. It certainly
won't; but nevertheless it doesn't make abort-on-failing-malloc less
sensible strategy for a whole class of applications.

Besides, a glib application can set up some sort of emergency memory
pool or something, so that failed malloc doesn't necessarily lead to
immediate abort(). Same sort of science fiction as "graceful exit with
saving data on *any* failed malloc() call in any possible application
in any possible situation" which seems to be so popular here ;)

Best regards,
Yevgen

Kelsey Bjarnason

unread,
Jan 27, 2008, 10:49:42 AM1/27/08
to

Oh, good God. They didn't. Tell me they didn't.

One wonders how many applications they've screwed over with that bit of
asinine idiocy.

Malcolm should go work for them. He'd love it. "Errors? We don't do
errors, we just crash the app. Enjoy another piece of quality software
from the Gnome team."

Yevgen Muntyan

unread,
Jan 27, 2008, 6:54:01 PM1/27/08
to
Randy Howard wrote:
> On Sun, 27 Jan 2008 16:12:01 -0600, William Ahern wrote
> (in article <h6cv65-...@wilbur.25thandClement.com>):
>
>> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
>>> Malcolm McLean wrote:
>>>> Here are six functions implemented on top of xmalloc(). No C programmer
>>>> should have any triouble providing the implemetations, though replace
>>>> and getquote are non-trivial.
>>> [snip]
>>>> I've think we've got something quite powerful here, purely because none
>>>> of these functions can ever return null for out of memory conditions. It
>>>> massively simplifies string handling.
>>> Take a look at glib,
>>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>> glib is where bad ideas go to die. Now, if somebody just had the nerve to
>> tell them....
>
> :)
>
> You gdon't glike ghaving gall gyour gvariables gprexfed gwith g?

Why, you don't like the following code?

#include <glib.h>

gint main (gint argc, gchar **argv)
{
gchar *s = g_strdup ("Hello there!");
g_print ("%s\n", s);
g_free (s);
}

Yevgen Muntyan

unread,
Jan 27, 2008, 6:56:11 PM1/27/08
to
Kelsey Bjarnason wrote:
> On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
>
>> Malcolm McLean wrote:
>>> Here are six functions implemented on top of xmalloc(). No C programmer
>>> should have any triouble providing the implemetations, though replace
>>> and getquote are non-trivial.
>> [snip]
>>
>>> I've think we've got something quite powerful here, purely because none
>>> of these functions can ever return null for out of memory conditions.
>>> It massively simplifies string handling.
>> Take a look at glib,
>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>
> Oh, good God. They didn't. Tell me they didn't.
>
> One wonders how many applications they've screwed over with that bit of
> asinine idiocy.

One wonders why one wonders about that only after he learns about
g_malloc. Perhaps because those applications aren't actually screwed?

cr88192

unread,
Jan 27, 2008, 8:13:50 PM1/27/08
to

"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
news:VMednX0onuvkPwHa...@comcast.com...

I usually use a garbage collector.


if the app runs out of memory (rare, since I usually use primarily static
memory-management approaches, but I can be lazy sometimes), the allocator
returns NULL.

now, crashing the app is just lazy, but it is possibly justified on the
grounds that on modern systems, running out of memory is rare enough that
this is justified (actually, it may well be justified to crash the app
before this limit, setting some sort of critical upper bound on memory
usage, and provoking the dev to reduce the footprint).

however, often NULL works just as well, because, as a general rule accessing
memory through a NULL pointer will crash the app anyways (most of the time,
address 0 being set to no-access).

this would be, assuming the issue is not handled.


better though, would be an exception handling system, namely, we crash only
if the out-of-memory exception goes unhandled. now, this is less nice in C,
which lacks a good exception system (nor the language features to really
implement one).

that is not to say, however, that a crude one could not be built around
setjmp/longjmp (library feature), or could be added, for example, as a
compiler syntax extension that rewrites exception handlers into the library
feature's form.


thus, in this case, an unhandled exception thus results in an abort (sadly,
an actual 'crash' at this point is pointless, since the context of the
exception is already lost).

of course, another approach would be threaded or recursive exception
handling (in C, however, there would be present other problems, and
semantics which would be problematic to reconcile with the unwinding
variety).

the system could, likely, be made to handle both, with some handlers set to
behave in a recursive manner (more like signal) and others in an unwinding
manner (longjmp). for semantic reasons, likely an unwinding handler would
silently ignore any previous recursive handlers (them being invoked in an
essentially meaningless context).

throw:
if last handler is signal-style, invoke callback;
otherwise, unwind to last handler.

handler:
if correct exception, do handling actions, and resume execution post
handler;
if there is another unwinding handler, unwind to that handler;
else, rethrow an unhandled exception.


> --
> Eric Sosman
> eso...@ieee-dot-org.invalid

William Ahern

unread,
Jan 27, 2008, 8:38:01 PM1/27/08
to
Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
<snip>

> I'd think evolution crashed because it crashed. You can look at
> its list of bugs to see what I mean. If it was abort() inside
> g_malloc(), then it probably leaked so much that it indeed has
> eaten everything and asked for more. In which case you can't
> really blame glib ;)

Actually, it was usually Galeon/Gecko which leaked, or rather whose leaks
would begin to trigger out-of-memory errors. But that's beside the point.
I'd much rather that Evolution fail to open a message than to exit entirely.

> (Here I'd be actually grateful if such applications were killed
> immediately, because they first freeze X, and I've got to wait
> for ten minutes to switch to console and kill the application.
> They just don't die themselves.)

If these were the only choices (crashing applications or a frozen screen),
I'd be more agreeable.

There were many bad spots in Evolution, but mostly the code was OK (I've
combed through much of it). Evolution had to deal with bad UTF encodings,
malformed MIME, networks coming up and going down. Handling memory
allocation failures would hardly add much in the way of complexity or
effort.

> >
> > In my experience, glib-based applications "mostly" work. Not sure whether
> > that has more to do w/ the xmalloc() wrapper, or other issues.

> There is no xmalloc() wrapper in glib. Anyway, have you never
> seen "mostly working" application which do not use glib? Bugs
> are everywhere, on all platforms. Do you have a real base for
> saying that g_malloc() is somehow responsible for crashes you
> have seen? Something other than "evolution crashed", that is,
> or "similar applications" (similar glib-based applications
> which open messages, huh?).

I know for a fact that Evolution and similar applications have exited
because their malloc wrapper decided to exit. They've also crashed for
numerous other reasons. Bugs are bugs, but defective by design is hardly
excusable.

Exiting on malloc failure makes sense for a utility like sort(1). It doesn't
make sense for desktop applications, unless there's a separate strategy,
like a multi-process configuration where a component exiting is part of the
design of handling errors and making a best-effort recovery.

It makes sense for sort(1) because it categorically cannot perform its task
on a failure. And its practical because sort is usually just a sub-component
in a larger work. Sort can exit without killing the script or application
which called it.

> You know, I have heard things like you are saying only from
> people who talk about xmalloc() and related things. Never from
> users. Why is that? Perhaps because buggy applications are
> buggy applications, not some poor creatures crashing because
> glib memory handling is broken?

Users are, sadly, inured to this issue. Nor can they discern the reason for
failure, so they aren't capable of judging the cost/benefit of any
particular behavior.

You sort of missed part of my point regarding Evolution. What I was
experiencing was a denial of service caused by processing untrusted data.
And by using glib you have no recourse. Indeed, much of glib's functionality
is simply a rehash of, by now, widely supported library interfaces, but with
the feature of exiting when memory becomes tight.

<snip>


> > One of my rules of thumb is that if a network daemon uses glib, I
> > automatically exclude it from consideration. I can deal when an application
> > crashes and destroys my work. I don't want to be responsible for installing
> > an application which crashes and destroys or interrupts _other_ people's
> > work.

> It's fine, nobody promiced glib will work for any program. It certainly
> won't; but nevertheless it doesn't make abort-on-failing-malloc less
> sensible strategy for a whole class of applications.

The problem is that such a strategy is usually the wrong one for the class
of applications which glib serves: desktop applications, and increasingly
network daemon services. Both of those usually involve monolithic
applications doing complex tasks for which memory allocation failure is only
one of dozens or hundreds of exceptional conditions. And yet out of all of
them people will argue memory allocation alone can be completely ignored,
simply because it's too burdensome.

> Besides, a glib application can set up some sort of emergency memory
> pool or something, so that failed malloc doesn't necessarily lead to
> immediate abort(). Same sort of science fiction as "graceful exit with
> saving data on *any* failed malloc() call in any possible application
> in any possible situation" which seems to be so popular here ;)

It's not science fiction. It's just difficult. And sometimes the answer
involves not using C, rather than using C and choosing not to address the
problem.

Eric Sosman

unread,
Jan 27, 2008, 8:54:05 PM1/27/08
to
Kelsey Bjarnason wrote:
> [...]

> You persist in demonstrating you have no concept at all how to design
> software.

Malcolm believes that an assembly line worker with a hangnail
is within his rights to halt the entire factory, no matter what
the rest of the team might think.

Malcolm believes that a private whose rifle jams is justified
in surrendering his whole country, no matter what the generals and
presidents and commissars say.

Malcolm believes that one fouled spark plug should announce its
difficulty by blowing the whole car to smithereens.

Malcolm -- oh, what's the use?

--
Eric Sosman
eso...@ieee-dot-org.invalid

Randy Howard

unread,
Jan 27, 2008, 9:28:31 PM1/27/08
to
On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote
(in article <mplu65-...@spanky.localhost.net>):

> On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
>
>> Malcolm McLean wrote:
>>> Here are six functions implemented on top of xmalloc(). No C programmer
>>> should have any triouble providing the implemetations, though replace
>>> and getquote are non-trivial.
>>
>> [snip]
>>
>>> I've think we've got something quite powerful here, purely because none
>>> of these functions can ever return null for out of memory conditions.
>>> It massively simplifies string handling.
>>
>> Take a look at glib,
>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>
> Oh, good God. They didn't. Tell me they didn't.
>
> One wonders how many applications they've screwed over with that bit of
> asinine idiocy.

Sure. That's why seeing an app crash on a linux box is "no big
surprise" anymore. It's also one of the reasons I don't run Linux
anymore except when I absolutely have to. It's not the kernel's fault,
but it is a problem with the normal way the platform is deployed.

> Malcolm should go work for them. He'd love it. "Errors? We don't do
> errors, we just crash the app. Enjoy another piece of quality software
> from the Gnome team."

Do they employ anyone at all?

Ian Collins

unread,
Jan 27, 2008, 9:37:21 PM1/27/08
to
Randy Howard wrote:

> On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote:
>>
>> One wonders how many applications they've screwed over with that bit of
>> asinine idiocy.
>
> Sure. That's why seeing an app crash on a linux box is "no big
> surprise" anymore. It's also one of the reasons I don't run Linux
> anymore except when I absolutely have to. It's not the kernel's fault,
> but it is a problem with the normal way the platform is deployed.
>
<OT>Unlike some other platforms, Linux and UNIX platforms in general
offer the user a choice of desktop environments. One popular
alternative is written in TOL, which is better equipped to manage
dynamic memory</OT>

--
Ian Collins.

Yevgen Muntyan

unread,
Jan 27, 2008, 9:40:22 PM1/27/08
to
William Ahern wrote:
> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
> <snip>
>> I'd think evolution crashed because it crashed. You can look at
>> its list of bugs to see what I mean. If it was abort() inside
>> g_malloc(), then it probably leaked so much that it indeed has
>> eaten everything and asked for more. In which case you can't
>> really blame glib ;)
>
> Actually, it was usually Galeon/Gecko which leaked, or rather whose leaks
> would begin to trigger out-of-memory errors. But that's beside the point.
> I'd much rather that Evolution fail to open a message than to exit entirely.
>
>> (Here I'd be actually grateful if such applications were killed
>> immediately, because they first freeze X, and I've got to wait
>> for ten minutes to switch to console and kill the application.
>> They just don't die themselves.)
>
> If these were the only choices (crashing applications or a frozen screen),
> I'd be more agreeable.
>
> There were many bad spots in Evolution, but mostly the code was OK (I've
> combed through much of it). Evolution had to deal with bad UTF encodings,
> malformed MIME, networks coming up and going down. Handling memory
> allocation failures would hardly add much in the way of complexity or
> effort.

[snip]

> The problem is that such a strategy is usually the wrong one for the class
> of applications which glib serves: desktop applications, and increasingly
> network daemon services. Both of those usually involve monolithic
> applications doing complex tasks for which memory allocation failure is only
> one of dozens or hundreds of exceptional conditions.

This is very very wrong. A typical GUI application does not do a
switch like

switch (problem_to_handle)
{
...
}

to which you could add

case ALLOC_FAILED:

It's usually different, you got the main loop which
got to spin, you got those controls you got to draw,
and you got those callbacks which actually do the
job. And the callbacks do one thing at a time, they
do not handle dozens of exceptional conditions at once,
they do not handle exceptional conditions at all
in fact.

> And yet out of all of
> them people will argue memory allocation alone can be completely ignored,
> simply because it's too burdensome.

No, because the effort would be gigantic, you would still fail to
do it properly, and at the end it would bring no benefit.

How would you test it? Imagine a toolkit which doesn't abort
on memory allocation failure: why would you have a slightest
reason to believe that given application won't just segfault
on malloc() failure? (The question which applies to all
applications which do try to handle malloc failure of course).
What you can be sure about is that there would be more chances
for an application to screw up and actually corrupt your data
or display wrong data.

All you can sensibly do on malloc() failure is to kill the
application. Maybe save the data you can save or something
(which you can do with glib). What else? Say, if malloc() failed
when the main loop code tries to process an event from Xlib, it
can start fail silently, it can be killed by an x error because
it failed to take into account some data it got (timestamp?),
it can grab the mouse and lock the X server, it can do many
other nasty things I can't make up right now.

Or, if malloc() failed when you tried to show a dialog telling
the user he got to call his mama, he won't call his mama! (Yes,
if the application crashed, the user will restart it, see the
dialog, and call his mama, users are like that. Those users who
are lucky enough to see an application aborting because memory
allocation failed. Randy Howard, you, and perhaps few other
people from comp.lang.c ;)

Of course I am talking about "small" allocations here, not
about stuff like allocating memory to load an image file (for
those g_malloc() is simply not used).

Perhaps in ideal world with ideal toolkits things would
be different, don't know about that. But I do know that
while dumb abort() is not the best possible solution,
talking about how it is easy to do things differently is
just a child talk. "Of course I would do it better!" Yeah.

Regards,
Yevgen

Yevgen Muntyan

unread,
Jan 27, 2008, 9:42:05 PM1/27/08
to

You mean those application will abort in the unexpected exception
handler instead of inside g_malloc()? Sure, that's certainly better.

Randy Howard

unread,
Jan 27, 2008, 9:46:07 PM1/27/08
to
On Sun, 27 Jan 2008 20:42:05 -0600, Yevgen Muntyan wrote
(in article <1ibnj.6922$fs4.1427@trnddc02>):

Is there some reason you have been appointed as glib's public defender?

;-)

Yevgen Muntyan

unread,
Jan 27, 2008, 10:01:40 PM1/27/08
to
Randy Howard wrote:
> On Sun, 27 Jan 2008 20:42:05 -0600, Yevgen Muntyan wrote
> (in article <1ibnj.6922$fs4.1427@trnddc02>):
>
>> Ian Collins wrote:
>>> Randy Howard wrote:
>>>> On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote:
>>>>> One wonders how many applications they've screwed over with that bit of
>>>>> asinine idiocy.
>>>> Sure. That's why seeing an app crash on a linux box is "no big
>>>> surprise" anymore. It's also one of the reasons I don't run Linux
>>>> anymore except when I absolutely have to. It's not the kernel's fault,
>>>> but it is a problem with the normal way the platform is deployed.
>>>>
>>> <OT>Unlike some other platforms, Linux and UNIX platforms in general
>>> offer the user a choice of desktop environments. One popular
>>> alternative is written in TOL, which is better equipped to manage
>>> dynamic memory</OT>
>> You mean those application will abort in the unexpected exception
>> handler instead of inside g_malloc()? Sure, that's certainly better.
>
> Is there some reason you have been appointed as glib's public defender?

I don't like smart arses who know nothing except how to use
word "idiot" and its derivatives. Not that glib needs to be
defended of course, since it's something that actually works
in real world, not like those smarties' smart ideas.

My original intention really was just to point out that
Malcolm ideas are not something unusual or broken by definition.
But then I read the replies, and replied myself, and I should
stop right here!

Yevgen

Ian Collins

unread,
Jan 27, 2008, 10:03:09 PM1/27/08
to

No, I mean the application can choose where in the call chain to catch
memory allocation failures and take appropriate action. It can also use
appropriate techniques not available to a C application to manage the
lifetime of allocated memory, reducing the risk of leaks leading to
premature memory exhaustion.

--
Ian Collins.

Yevgen Muntyan

unread,
Jan 27, 2008, 10:14:46 PM1/27/08
to
Ian Collins wrote:
> Yevgen Muntyan wrote:
>> Ian Collins wrote:
>>> Randy Howard wrote:
>>>> On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote:
>>>>> One wonders how many applications they've screwed over with that bit
>>>>> of asinine idiocy.
>>>> Sure. That's why seeing an app crash on a linux box is "no big
>>>> surprise" anymore. It's also one of the reasons I don't run Linux
>>>> anymore except when I absolutely have to. It's not the kernel's
>>>> fault, but it is a problem with the normal way the platform is deployed.
>>>>
>>> <OT>Unlike some other platforms, Linux and UNIX platforms in general
>>> offer the user a choice of desktop environments. One popular
>>> alternative is written in TOL, which is better equipped to manage
>>> dynamic memory</OT>
>> You mean those application will abort in the unexpected exception
>> handler instead of inside g_malloc()? Sure, that's certainly better.
>
> No, I mean the application can choose where in the call chain to catch
> memory allocation failures and take appropriate action.

Sweet theory. And where is that, main()? Or where do you call the
function/method which starts the main loop? And, more importantly,
which so-much-better other-toolkit applications actually do this?
And, what of the above is impossible in C with glib (since we talk
theory here, not what applications really do)?

> It can also use
> appropriate techniques not available to a C application to manage the
> lifetime of allocated memory, reducing the risk of leaks leading to
> premature memory exhaustion.

True. The Other Language does have nice things. But then the
Other Language is better (if better) not because of some glib,
but because of the language features ;)

Yevgen

Randy Howard

unread,
Jan 27, 2008, 10:16:22 PM1/27/08
to
On Sun, 27 Jan 2008 21:01:40 -0600, Yevgen Muntyan wrote
(in article <oAbnj.6924$fs4.3455@trnddc02>):

> Randy Howard wrote:
>> On Sun, 27 Jan 2008 20:42:05 -0600, Yevgen Muntyan wrote
>> (in article <1ibnj.6922$fs4.1427@trnddc02>):
>>
>>> Ian Collins wrote:
>>>> Randy Howard wrote:
>>>>> On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote:
>>>>>> One wonders how many applications they've screwed over with that bit of
>>>>>> asinine idiocy.
>>>>> Sure. That's why seeing an app crash on a linux box is "no big
>>>>> surprise" anymore. It's also one of the reasons I don't run Linux
>>>>> anymore except when I absolutely have to. It's not the kernel's fault,
>>>>> but it is a problem with the normal way the platform is deployed.
>>>>>
>>>> <OT>Unlike some other platforms, Linux and UNIX platforms in general
>>>> offer the user a choice of desktop environments. One popular
>>>> alternative is written in TOL, which is better equipped to manage
>>>> dynamic memory</OT>
>>> You mean those application will abort in the unexpected exception
>>> handler instead of inside g_malloc()? Sure, that's certainly better.
>>
>> Is there some reason you have been appointed as glib's public defender?
>
> I don't like smart arses who know nothing except how to use
> word "idiot" and its derivatives.

When you refer to someone that holds a different opinion than you do as
a "smart arse who knows nothing", how is that any better than calling
someone an "idiot"? I'm curious how you arrived at this distinction,
as well as how you determined what they don't know from afar.

> Not that glib needs to be
> defended of course, since it's something that actually works
> in real world, not like those smarties' smart ideas.

That people have written and deployed applications with glib doesn't
mean that its design is good, or bad on its own. All it means is
somebody typed 'make' and hit the enter key and out popped a binary
which people use.

> My original intention really was just to point out that
> Malcolm ideas are not something unusual or broken by definition.

What this amounts to is one of those so-called "religious" disputes
about which programmers love to argue, yet nobody every gets
"converted". In a word, pointless. Well, there is an outside chance
that somebody that hasn't formed an opinion yet might learn something
from the debate that would help them come to a conclusion. However,
calling each other "idiot", or "smart arses" doesn't do much to help
that process along.

Randy Howard

unread,
Jan 27, 2008, 10:17:07 PM1/27/08
to
On Sun, 27 Jan 2008 17:54:01 -0600, Yevgen Muntyan wrote
(in article <tQ8nj.4577$z_6.3302@trnddc06>):

> Randy Howard wrote:
>> On Sun, 27 Jan 2008 16:12:01 -0600, William Ahern wrote
>> (in article <h6cv65-...@wilbur.25thandClement.com>):
>>
>>> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
>>>> Malcolm McLean wrote:
>>>>> Here are six functions implemented on top of xmalloc(). No C programmer
>>>>> should have any triouble providing the implemetations, though replace
>>>>> and getquote are non-trivial.
>>>> [snip]
>>>>> I've think we've got something quite powerful here, purely because none
>>>>> of these functions can ever return null for out of memory conditions. It
>>>>> massively simplifies string handling.
>>>> Take a look at glib,
>>>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>>> glib is where bad ideas go to die. Now, if somebody just had the nerve to
>>> tell them....
>>
>>>>
>>

>> You gdon't glike ghaving gall gyour gvariables gprexfed gwith g?
>
> Why, you don't like the following code?
>
> #include <glib.h>
>
> gint main (gint argc, gchar **argv)
> {
> gchar *s = g_strdup ("Hello there!");
> g_print ("%s\n", s);
> g_free (s);
> }

Not particularly. Should I?

Yevgen Muntyan

unread,
Jan 27, 2008, 10:25:08 PM1/27/08
to

You have it quoted. If you mean that one may talk "idiocy"
but I shouldn't refer to him as "smart arse" (since as
a glib user I conclude from his words that I am an idiot
who screws applications over), then I will disagree.


>> Not that glib needs to be
>> defended of course, since it's something that actually works
>> in real world, not like those smarties' smart ideas.
>
> That people have written and deployed applications with glib doesn't
> mean that its design is good, or bad on its own. All it means is
> somebody typed 'make' and hit the enter key and out popped a binary
> which people use.

Yep. A binary which does what it intends to do, "works".

>> My original intention really was just to point out that
>> Malcolm ideas are not something unusual or broken by definition.
>
> What this amounts to is one of those so-called "religious" disputes
> about which programmers love to argue, yet nobody every gets
> "converted". In a word, pointless. Well, there is an outside chance
> that somebody that hasn't formed an opinion yet might learn something
> from the debate that would help them come to a conclusion. However,
> calling each other "idiot", or "smart arses" doesn't do much to help
> that process along.


Sorry, you mean that that someone could learn something from
this:

"""
That's why seeing an app crash on a linux box is "no big surprise"
anymore. It's also one of the reasons I don't run Linux anymore
except when I absolutely have to
"""

or

"""
One wonders how many applications they've screwed over with that
bit of asinine idiocy.
"""

but he won't be able to because of my "smart arse"? I apologize
for my rude (or whatever you don't like here) language then.

William Ahern

unread,
Jan 27, 2008, 10:42:04 PM1/27/08
to
Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
<snip>
> This is very very wrong. A typical GUI application does not do a
> switch like

> switch (problem_to_handle)
> {
> ...
> }

> to which you could add

> case ALLOC_FAILED:

> It's usually different, you got the main loop which
> got to spin, you got those controls you got to draw,
> and you got those callbacks which actually do the
> job. And the callbacks do one thing at a time, they
> do not handle dozens of exceptional conditions at once,
> they do not handle exceptional conditions at all
> in fact.

Is that why applications crash when, using a file dialog box, I attempt to
save a file into a directory I don't have write permission to?

To my mind, there's no difference in effort required to handle a NULL return
from fopen(), than a NULL return from malloc(). Maybe more typing. This is
just a resource acquisition issue, and even if you had infinite memory it's
a pattern you still have to deal with.

As to main loops, I'm very familiar with these. I write event based async-io
network software, using an event dispatcher exactly like a GUI application
might. I create and use more callback interfaces than I probably should.
When I accept a connection, I might--though, try not to--do dozens of
allocations. I try to write my code so any allocation failure is handled
gracefully. I don't need a gigantic switch statement, or special language
constructs. One designs the code to deal with such a circumstances as a
matter of course. You minimize dependencies, isolate access to shared data,
postpone commiting to a particular state wrt to that context until you've
acquired a minimal set of resources, etc. Any non-trivial application
usually has multiple contexts within which such intermediate failures can be
contained, with practical benefit.

Granted, I've not done much work with X11 applications, or GUI applications
in general. But, I fail to understand how a caveat wrt to X11
justifies--absent other reasons--exiting when a string cannot be allocated.

> > And yet out of all of
> > them people will argue memory allocation alone can be completely ignored,
> > simply because it's too burdensome.
>

<snip>


> Of course I am talking about "small" allocations here, not
> about stuff like allocating memory to load an image file (for
> those g_malloc() is simply not used).

There's absolutely no qualitative difference between small and large
allocations without reference to other circumstances (number of allocations,
etc). If I have 4GB of memory, what does it matter that a 10MB allocation is
checked but not a 12B allocation? When the application approaches the limit
its not likely that one will be more susceptible to failure than the other.
The choice is then arbitrary and almost absurd. Better, for consistency, to
not bother at all.

CBFalconer

unread,
Jan 27, 2008, 10:58:46 PM1/27/08
to
Kelsey Bjarnason wrote:
>
... snip ...

>
> Ah, right, so if it can't allocate enough memory to process that
> large select you just issued, it makes perfect sense to crash and
> die, taking with it any unstored data, rather than report back
> that there's insufficient memory. Yeah, well, not like *data*
> matters, not in a *database* app.

Are you writing performance specifications for Microsoft?

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.


--
Posted via a free Usenet account from http://www.teranews.com

Yevgen Muntyan

unread,
Jan 27, 2008, 11:17:54 PM1/27/08
to
William Ahern wrote:
> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
> <snip>
>> This is very very wrong. A typical GUI application does not do a
>> switch like
>
>> switch (problem_to_handle)
>> {
>> ...
>> }
>
>> to which you could add
>
>> case ALLOC_FAILED:
>
>> It's usually different, you got the main loop which
>> got to spin, you got those controls you got to draw,
>> and you got those callbacks which actually do the
>> job. And the callbacks do one thing at a time, they
>> do not handle dozens of exceptional conditions at once,
>> they do not handle exceptional conditions at all
>> in fact.
>
> Is that why applications crash when, using a file dialog box, I attempt to
> save a file into a directory I don't have write permission to?


No idea, ask the developers of that buggy application.
Failed fopen() is not an exceptional condition. Failed
malloc() is. Or we are using different vocabularies.


> To my mind, there's no difference in effort required to handle a NULL return
> from fopen(), than a NULL return from malloc(). Maybe more typing.


Then you are just really good. Because it's enormously more
typing. And more than that, it's more design questions too:
"what do I do in this situation, which I can't even possibly
test?" All this apart from real problems you have to solve.
Yes, *real*. No, g_malloc() aborting an application is not
a real problem. Not for a regular desktop application.

> This is
> just a resource acquisition issue, and even if you had infinite memory it's
> a pattern you still have to deal with.


Except you don't open files twenty times in a row in every function
in your application. Memory is quite a different kind of resource.
Different in how you use it, you know.


> As to main loops, I'm very familiar with these. I write event based async-io
> network software, using an event dispatcher exactly like a GUI application
> might. I create and use more callback interfaces than I probably should.
> When I accept a connection, I might--though, try not to--do dozens of
> allocations. I try to write my code so any allocation failure is handled
> gracefully. I don't need a gigantic switch statement, or special language
> constructs. One designs the code to deal with such a circumstances as a
> matter of course. You minimize dependencies, isolate access to shared data,
> postpone commiting to a particular state wrt to that context until you've
> acquired a minimal set of resources, etc. Any non-trivial application
> usually has multiple contexts within which such intermediate failures can be
> contained, with practical benefit.
>
> Granted, I've not done much work with X11 applications, or GUI applications
> in general. But, I fail to understand how a caveat wrt to X11
> justifies--absent other reasons--exiting when a string cannot be allocated.


So you click Save button then click Close. The application failed to
process Save click because it failed to allocate memory for the event
structure to put into the event queue, but then it successfully handled
Close because at the same time yet another document was closed and
some memory returned to the malloc pool. You may not just lose events
like that. *Everything* must be done in order, or the application is
doomed, and the best it can do is to try to exit as nicely as it can
(like save data or whatever). It can't just pretend nothing happened.


>>> And yet out of all of
>>> them people will argue memory allocation alone can be completely ignored,
>>> simply because it's too burdensome.
> <snip>
>> Of course I am talking about "small" allocations here, not
>> about stuff like allocating memory to load an image file (for
>> those g_malloc() is simply not used).
>
> There's absolutely no qualitative difference between small and large
> allocations without reference to other circumstances (number of allocations,
> etc). If I have 4GB of memory, what does it matter that a 10MB allocation is
> checked but not a 12B allocation? When the application approaches the limit
> its not likely that one will be more susceptible to failure than the other.
> The choice is then arbitrary and almost absurd. Better, for consistency, to
> not bother at all.

All allocations are checked. It's what you do when they fail is
different. If malloc(12) failed, then you are screwed because
all your code wants memory. No memory => application isn't working.
So you just don't try to handle (that is do something and not exit
the application) possible malloc() failure when you are concatenating
two strings to make up a string to display. Absurd, fine, I'll be
delighted to see an application which handles malloc() failure
when it draws a menu label (it *is* possible, it just doesn't
make sense).

CBFalconer

unread,
Jan 27, 2008, 11:20:21 PM1/27/08
to
Randy Howard wrote:
>
... snip ...

>
> What this amounts to is one of those so-called "religious"
> disputes about which programmers love to argue, yet nobody every
> gets "converted". In a word, pointless. Well, there is an
> outside chance that somebody that hasn't formed an opinion yet
> might learn something from the debate that would help them come
> to a conclusion. However, calling each other "idiot", or "smart
> arses" doesn't do much to help that process along.

Well, that depends on your definition of 'that process'. If it is
'an efficient method of engendering flamewars', I think it has been
admirably assisted.

CBFalconer

unread,
Jan 28, 2008, 1:09:07 AM1/28/08
to
Yevgen Muntyan wrote:
> William Ahern wrote:
>
... snip ...

>
>> To my mind, there's no difference in effort required to handle a
>> NULL return from fopen(), than a NULL return from malloc(). Maybe
>> more typing.
>
> Then you are just really good. Because it's enormously more
> typing. And more than that, it's more design questions too:
> "what do I do in this situation, which I can't even possibly
> test?" All this apart from real problems you have to solve.
> Yes, *real*. No, g_malloc() aborting an application is not
> a real problem. Not for a regular desktop application.

Oh? Do you detect a major difference in typing between:

ptr = xmalloc(sizeof *ptr);
and
if (!(ptr = malloc(sizeof *ptr))) fixit(sizeof *ptr);

and you can actually select the appropriate fixit function!!

Ian Collins

unread,
Jan 28, 2008, 1:47:05 AM1/28/08
to
Yevgen Muntyan wrote:
> Ian Collins wrote:
>> Yevgen Muntyan wrote:
>>> Ian Collins wrote:
>>>> Randy Howard wrote:
>>>>> On Sun, 27 Jan 2008 09:49:42 -0600, Kelsey Bjarnason wrote:
>>>>>> One wonders how many applications they've screwed over with that bit
>>>>>> of asinine idiocy.
>>>>> Sure. That's why seeing an app crash on a linux box is "no big
>>>>> surprise" anymore. It's also one of the reasons I don't run Linux
>>>>> anymore except when I absolutely have to. It's not the kernel's
>>>>> fault, but it is a problem with the normal way the platform is
>>>>> deployed.
>>>>>
>>>> <OT>Unlike some other platforms, Linux and UNIX platforms in general
>>>> offer the user a choice of desktop environments. One popular
>>>> alternative is written in TOL, which is better equipped to manage
>>>> dynamic memory</OT>
>>> You mean those application will abort in the unexpected exception
>>> handler instead of inside g_malloc()? Sure, that's certainly better.
>>
>> No, I mean the application can choose where in the call chain to catch
>> memory allocation failures and take appropriate action.
>
> Sweet theory. And where is that, main()? Or where do you call the
> function/method which starts the main loop? And, more importantly,
> which so-much-better other-toolkit applications actually do this?

That I can't answer, it's been too long since I've worked with that code.

> And, what of the above is impossible in C with glib (since we talk
> theory here, not what applications really do)?
>

Using exceptions to handle allocation failure at a point where something
sensible can be done. This may be at the point of allocation, or it may
be many calls away. This removes the necessity to check each call for
failure.

--
Ian Collins.

Yevgen Muntyan

unread,
Jan 28, 2008, 1:53:24 AM1/28/08
to
CBFalconer wrote:
> Yevgen Muntyan wrote:
>> William Ahern wrote:
>>
> ... snip ...
>>> To my mind, there's no difference in effort required to handle a
>>> NULL return from fopen(), than a NULL return from malloc(). Maybe
>>> more typing.
>> Then you are just really good. Because it's enormously more
>> typing. And more than that, it's more design questions too:
>> "what do I do in this situation, which I can't even possibly
>> test?" All this apart from real problems you have to solve.
>> Yes, *real*. No, g_malloc() aborting an application is not
>> a real problem. Not for a regular desktop application.
>
> Oh? Do you detect a major difference in typing between:
>
> ptr = xmalloc(sizeof *ptr);
> and
> if (!(ptr = malloc(sizeof *ptr))) fixit(sizeof *ptr);
>
> and you can actually select the appropriate fixit function!!

Do you suggest that this toy example is scalable? No, in this
toy example there isn't much more typing.

Malcolm McLean

unread,
Jan 28, 2008, 4:21:35 AM1/28/08
to

<vipp...@gmail.com> wrote in message
> On Jan 27, 5:42 pm, "Malcolm McLean" <regniz...@btinternet.com> wrote:

> int main(void) {
>
> FILE *fp = fopen("/dev/zero", "r"); /* assume UNIX & fopen doesn't
> fail */
> char *foo, *bar;
> foo = dup("Hello, World"); /* assume success */
> bar = getline(fp); /* obviously this will fail to allocate enough
> memory, will quit and a memory leak will occur because the return
> value of dup() was not freed */
> free(bar); free(foo);
> return 0;
> }
> -- snip.c --
>
> I can think of a *lot* more reasons why I would not want my program to
> terminate because an allocation failed.
> These solutions are horrible, I strongly suggest that you avoid using
> them in your own programs.
>
int main(int argc, char **argv)
{
FILE *fp;
char *line;
int i = 1;

if(argc != 2)
exit(EXIT_FAILURE);
fp = fopen(argv[1], "r");
if(!fp)
{
fprintf(stderr, "Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
while(line = getline(fp))
{
printf("%d: %s", i++, line);
free(line);
}
fclose(fp);
return 0;
}

There's a program to print a file, prepending the line number. See how
simple it is, because we don't have to do any error processing?

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

santosh

unread,
Jan 28, 2008, 4:30:43 AM1/28/08
to
CBFalconer wrote:

> Kelsey Bjarnason wrote:
>>
> ... snip ...
>>
>> Ah, right, so if it can't allocate enough memory to process that
>> large select you just issued, it makes perfect sense to crash and
>> die, taking with it any unstored data, rather than report back
>> that there's insufficient memory. Yeah, well, not like *data*
>> matters, not in a *database* app.
>
> Are you writing performance specifications for Microsoft?

He was being sarcastic in criticising Malcolm's design strategies.

Richard Heathfield

unread,
Jan 28, 2008, 5:38:14 AM1/28/08
to
Malcolm McLean said:

<program snipped>



> There's a program to print a file,

...which exhibits undefined behaviour because you call a variadic function
without a valid function prototype in scope.

> prepending the line number. See how
> simple it is, because we don't have to do any error processing?

Correction: see how simple it is, because you didn't *bother* to do any
error processing.

The computer on which I type this is connected to a UPS. Since the power
hardly ever fails, why do I bother? The UPS has a mains lead ending in a
plug with a fuse in it. Since it hardly ever happens that too much power
goes through the lead, why bother? The plug fits into a surge protector.
(In fact, the UPS is surge-protected, too.) The router also plugs into
this surge protector. But why bother, since surges are so rare? And the
surge protector has its own fuse. Why bother with /that/? And if we /are/
bothering with that, why bother to fuse-protect anything that plugs into
it?

You seem to have fundamentally misunderstood the importance of defensive
programming.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

Malcolm McLean

unread,
Jan 28, 2008, 6:10:54 AM1/28/08
to

"Richard Heathfield" <r...@see.sig.invalid> wrote in message

> Malcolm McLean said:
>
> <program snipped>
>
>> There's a program to print a file,
>
> ...which exhibits undefined behaviour because you call a variadic function
> without a valid function prototype in scope.
>
>> prepending the line number. See how
>> simple it is, because we don't have to do any error processing?
>
> Correction: see how simple it is, because you didn't *bother* to do any
> error processing.
>
> The computer on which I type this is connected to a UPS. Since the power
> hardly ever fails, why do I bother? The UPS has a mains lead ending in a
> plug with a fuse in it. Since it hardly ever happens that too much power
> goes through the lead, why bother? The plug fits into a surge protector.
> (In fact, the UPS is surge-protected, too.) The router also plugs into
> this surge protector. But why bother, since surges are so rare? And the
> surge protector has its own fuse. Why bother with /that/? And if we /are/
> bothering with that, why bother to fuse-protect anything that plugs into
> it?
>
> You seem to have fundamentally misunderstood the importance of
> defensive programming.
>
It depends on the costs.
Here we've taken virtually all the error-processing out and passed it to
xmalloc, which will exit with an error message if anything goes wrong. We
could write the program so that it is not line-based at all. Then it won't
crash out if someone passes it a malformed line. But it would be harder to
read and understand.
The main cost of a program is usually the development cost, and then the
costs of maintainence. That's what you've got to attack. Convoluted logic
for every bit of string processing, because the machine might run out of
memory, isn't helping anyone, unless the application really must never
terminate.

Richard Heathfield

unread,
Jan 28, 2008, 6:19:56 AM1/28/08
to
Malcolm McLean said:

<snip>

> Here we've taken virtually all the error-processing out and passed it to
> xmalloc, which will exit with an error message if anything goes wrong.

If the cabin temperature drops below minimum required level, cut the
engines. If a slat deploys wrongly on the starboard wing, cut the engines.
If there's an oil pressure drop, cut the engines. If the aircraft stalls,
cut the engines. If the CD player on the flight deck fails, cut the
engines. If the co-pilot dozes off, cut the engines.

I will not fly with McLean Airways.

santosh

unread,
Jan 28, 2008, 7:14:19 AM1/28/08
to
Malcolm McLean wrote:

>
> "Richard Heathfield" <r...@see.sig.invalid> wrote in message
>> Malcolm McLean said:
>>
>> <program snipped>
>>
>>> There's a program to print a file,
>>
>> ...which exhibits undefined behaviour because you call a variadic
>> function without a valid function prototype in scope.
>>
>>> prepending the line number. See how
>>> simple it is, because we don't have to do any error processing?
>>
>> Correction: see how simple it is, because you didn't *bother* to do
>> any error processing.
>>
>> The computer on which I type this is connected to a UPS. Since the
>> power hardly ever fails, why do I bother? The UPS has a mains lead
>> ending in a plug with a fuse in it. Since it hardly ever happens that
>> too much power goes through the lead, why bother? The plug fits into
>> a surge protector. (In fact, the UPS is surge-protected, too.) The
>> router also plugs into this surge protector. But why bother, since
>> surges are so rare? And the surge protector has its own fuse. Why
>> bother with /that/? And if we /are/ bothering with that, why bother
>> to fuse-protect anything that plugs into it?
>>
>> You seem to have fundamentally misunderstood the importance of
>> defensive programming.
>>
> It depends on the costs.

[ ... ]

> The main cost of a program is usually the development cost, and then
> the costs of maintainence.

So the cost to the poor users from using an ill-designed program is okay
as long as it's development was easier is it?

> That's what you've got to attack.
> Convoluted logic for every bit of string processing, because the
> machine might run out of memory, isn't helping anyone, unless the
> application really must never terminate.

Typically you don't need to duplicate the logic for error handling at
every potential place of occurrence. Typically you can group all these
potential sites of errors into a few well defined categories, and a
single handler is usually sufficient for each such category. This means
that a moderately complex application will have, say, two or three
different out-of-memory handlers, which, IMO, is not convoluted or
undoable.

Army1987

unread,
Jan 28, 2008, 7:43:36 AM1/28/08
to
Malcolm McLean wrote:

> Here are six functions implemented on top of xmalloc(). No C programmer
> should have any triouble providing the implemetations, though replace and
> getquote are non-trivial.
>

> char *dup(const char *str);
> char *cat(const char *str1, const char *str2);
> char *catandkill(char *str1, const char *str2);
> char *tok(const char *str, const char *delims, char **end);
> char *midstr(const char *str, int idx, int len);
> char *replace(const char *str, const char *pattern, const char *rep);
> char *getquote(const char *str, char quote, char escape, char **end);
> char *getline(FILE *fp);
>
> All return strings allocated with xmalloc().
No xmalloc needed.

#include <string.h>
#include <stdlib.h>

#if SLACK_PROGRAMMER
#define return else exit(EXIT_FAILURE); return
#endif

char *dup(const char *orig)
/* this function has the same name of a POSIX function to duplicate *
* file descriptors. Anything more imaginative? */
{
size_t size = strlen(orig) + 1;
char *new = malloc(size);
if (new != NULL)
memcpy(new, orig, size);
return new;
}

char *dup(const char *str1, const char *str2)
{
size_t s1 = strlen(str1), s2 = strlen(str2) + 1;
char *new = malloc(size);
if (new != NULL) {
memcpy(new, str1, s1);
memcpy(new + s1, str2, s2);
}
return new;
}

char *catandkill(const char *s1, const char s2)
/*requires s1 to point at the beginning of a malloc()ated block*/
{
char *new = s1 ? cat(s1, s2) : dup(s2);
if (new != NULL)
free(s1);
return new;
}

And so on.
--
Army1987 (Replace "NOSPAM" with "email")

Army1987

unread,
Jan 28, 2008, 8:05:49 AM1/28/08
to
Malcolm McLean wrote:

> Here are six functions implemented on top of xmalloc(). No C programmer
> should have any triouble providing the implemetations, though replace and
> getquote are non-trivial.
>
> char *dup(const char *str);
> char *cat(const char *str1, const char *str2);
> char *catandkill(char *str1, const char *str2);
> char *tok(const char *str, const char *delims, char **end);
> char *midstr(const char *str, int idx, int len);
> char *replace(const char *str, const char *pattern, const char *rep);
> char *getquote(const char *str, char quote, char escape, char **end);
> char *getline(FILE *fp);
>
> All return strings allocated with xmalloc().
No xmalloc needed.

#include <string.h>
#include <stdlib.h>

#if SLACK_PROGRAMMER
#define return else { fputs("Cannot allocate memory\n", stderr); \

Eric Sosman

unread,
Jan 28, 2008, 8:56:33 AM1/28/08
to
Malcolm McLean wrote:
>
> int main(int argc, char **argv)
> {
> FILE *fp;
> char *line;
> int i = 1;
>
> if(argc != 2)
> exit(EXIT_FAILURE);
> fp = fopen(argv[1], "r");
> if(!fp)
> {
> fprintf(stderr, "Can't open %s\n", argv[1]);
> exit(EXIT_FAILURE);
> }
> while(line = getline(fp))
> {
> printf("%d: %s", i++, line);
> free(line);
> }
> fclose(fp);
> return 0;
> }
>
> There's a program to print a file, prepending the line number. See how
> simple it is, because we don't have to do any error processing?

Why does the program test the value of argc? If it's
acceptable for the program to die abruptly on an allocation
failure, surely it's equally acceptable to die with SIGSEGV
if too few arguments are provided, or to blunder merrily
onwards if there are too many.

Why does the program test the value returned by fopen()?
If it's acceptable for the program to die abruptly on an
allocation failure, surely it's equally acceptable to die
with SIGSEGV when calling getline(NULL).

In other words, why don't you have the same "What? Me worry?"
attitude towards usage errors and I/O errors that you do toward
allocation failures? (And you still haven't described what the
"familiar friend" getline() should do if an I/O error occurs.)

The really simple-minded thing about this program, though,
is that it shouldn't be allocating any dynamic memory at all!
It could be a character-at-a-time loop, just testing for '\n'
as it buzzes merrily along -- but no: Illustrations of how simple
things are must always be more complicated than they need to be.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Malcolm McLean

unread,
Jan 28, 2008, 9:36:33 AM1/28/08
to

"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message #
The point is that the string functions are far more usable when they cannot
encounter fail conditions. If every call to getline() needs to be checked,
not for file termination but for memory failure, the program is a mess.
Similarly with the other functions.

>
> The really simple-minded thing about this program, though,
> is that it shouldn't be allocating any dynamic memory at all!
> It could be a character-at-a-time loop, just testing for '\n'
> as it buzzes merrily along -- but no: Illustrations of how simple
> things are must always be more complicated than they need to be.
>
In my opinion that's the hacker's answer.

Eric Sosman

unread,
Jan 28, 2008, 10:36:40 AM1/28/08
to
Malcolm McLean wrote:
> [...]

> The point is that the string functions are far more usable when they
> cannot encounter fail conditions.

The point is that "cannot encounter" is not the same thing
as "cannot survive."

>> The really simple-minded thing about this program, though,
>> is that it shouldn't be allocating any dynamic memory at all!
>> It could be a character-at-a-time loop, just testing for '\n'
>> as it buzzes merrily along -- but no: Illustrations of how simple
>> things are must always be more complicated than they need to be.
>>
> In my opinion that's the hacker's answer.

I guess you define "hacker" as "someone whose programs work."
What's your word for "someone whose programs fail when they exhaust
resources they didn't actually need?"

--
Eric Sosman
eso...@ieee-dot-org.invalid

Malcolm McLean

unread,
Jan 28, 2008, 10:43:32 AM1/28/08
to

"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
hacks work. That's part of the word's definition.
I think what we are looking for is what Dann called "sloppy programming".
I'd call it "loose programming" That is, program that take resources they
don't strictly need, in order to reduce programming time, and quit when they
strictly could continue, for the same reason. So the opposite of "tight
code".

Ben Bacarisse

unread,
Jan 28, 2008, 10:54:47 AM1/28/08
to
"Malcolm McLean" <regn...@btinternet.com> writes:

<snip example to show:>


> while(line = getline(fp))
> {
> printf("%d: %s", i++, line);
> free(line);
> }

I think you taken the wrong path. You've made the above simple by
putting the error recovery too deep (in the library). Once execution
has gone deep, the information about what do about the error is
usually lost -- so we are left with your example of a use-called
error function can't do the one thing the caller might do which is to
request less memory.

Simple error handling is so common that you can factor it out as a
function if you want your users to have a simple interface:

void *never_null(void *p)
{
if (!p) exit(EXIT_FAILURE);
return p;
}

If your library can return a NULL and users don't want one, tell then
to call:

while(line = never_null(getline(fp)))

instead of getline. This way they can have simplicity *or* control.
If you are worried about the loss of type-checking, you can compile
with

#define never_null(p) (p)

to be sure.

[Aside: if your algorithms may request 0 bytes, you must ensure that
malloc(0) never returns NULL or this method will signal an error where
none exists.]

--
Ben.

Eric Sosman

unread,
Jan 28, 2008, 11:12:26 AM1/28/08
to
Malcolm McLean wrote:
>
> "Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
>> Malcolm McLean wrote:
>>> [...]
>>> The point is that the string functions are far more usable when they
>>> cannot encounter fail conditions.
>>
>> The point is that "cannot encounter" is not the same thing
>> as "cannot survive."
>>
>>>> The really simple-minded thing about this program, though,
>>>> is that it shouldn't be allocating any dynamic memory at all!
>>>> It could be a character-at-a-time loop, just testing for '\n'
>>>> as it buzzes merrily along -- but no: Illustrations of how simple
>>>> things are must always be more complicated than they need to be.
>>>>
>>> In my opinion that's the hacker's answer.
>>
>> I guess you define "hacker" as "someone whose programs work."
>> What's your word for "someone whose programs fail when they exhaust
>> resources they didn't actually need?"
>>
> hacks work. That's part of the word's definition.
> I think what we are looking for is what Dann called "sloppy
> programming". I'd call it "loose programming" That is, program that take
> resources they don't strictly need, in order to reduce programming time,
> and quit when they strictly could continue, for the same reason. So the
> opposite of "tight code".

In my opinion that's the spin doctor's answer.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Malcolm McLean

unread,
Jan 28, 2008, 11:19:40 AM1/28/08
to

"Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
The snag there is that getline() does return null. On end of input.

Like Perl's

while( $line = <INPUT> )
{
/* processing here */
}

This idiom is used in thousands of Perl scripts every day.

Kelsey Bjarnason

unread,
Jan 28, 2008, 4:06:57 AM1/28/08
to
[snips]

On Mon, 28 Jan 2008 14:36:33 +0000, Malcolm McLean wrote:

> The point is that the string functions are far more usable when they
> cannot encounter fail conditions.

You do not guarantee the string functions will not encounter fail
conditions; what you guarantee is that when fail conditions occur, the
program will abort rather than handle them gracefully.

> If every call to getline() needs to be
> checked, not for file termination but for memory failure, the program is
> a mess.

Depends how it's handled, now don't it? If any call to getline risks
having the application terminate with no way to even detect the failure,
then yes, the program is a mess.

Kelsey Bjarnason

unread,
Jan 28, 2008, 4:18:37 AM1/28/08
to
On Sun, 27 Jan 2008 22:58:46 -0500, CBFalconer wrote:

> Kelsey Bjarnason wrote:
>>
> ... snip ...
>>
>> Ah, right, so if it can't allocate enough memory to process that large
>> select you just issued, it makes perfect sense to crash and die, taking
>> with it any unstored data, rather than report back that there's
>> insufficient memory. Yeah, well, not like *data* matters, not in a
>> *database* app.
>
> Are you writing performance specifications for Microsoft?

No, I'm reverse-engineering them based on observer performance
characteristics. :)

Actually, we use MSSQL a fair bit around here, because a few apps we need
are sufficiently boneheaded to require it, and it alone. That said, the
only one I know of we have issues with isn't MSSQL's fault; it's on a
dodgy machine.

I prefer other things - MySQL for small stuff, sqlite for really small
stuff, postgres for bigger stuff and so on - but I can't honestly say
MSSQL is a steaming load of dingo kidneys based on direct personal
experience.

'Course, it _does_ require Windows, which is another matter - don't get
me started. :)

Ben Bacarisse

unread,
Jan 28, 2008, 12:44:03 PM1/28/08
to
"Malcolm McLean" <regn...@btinternet.com> writes:

> "Ben Bacarisse" <ben.u...@bsb.me.uk> wrote in message
>> "Malcolm McLean" <regn...@btinternet.com> writes:
>>
>> <snip example to show:>
>>> while(line = getline(fp))
>>> {
>>> printf("%d: %s", i++, line);
>>> free(line);
>>> }
>>
>> I think you taken the wrong path. You've made the above simple by
>> putting the error recovery too deep (in the library). Once execution
>> has gone deep, the information about what do about the error is
>> usually lost -- so we are left with your example of a use-called
>> error function can't do the one thing the caller might do which is to
>> request less memory.
>>
>> Simple error handling is so common that you can factor it out as a
>> function if you want your users to have a simple interface:
>>
>> void *never_null(void *p)
>> {
>> if (!p) exit(EXIT_FAILURE);
>> return p;
>> }

<snip bad example!>


>>
> The snag there is that getline() does return null. On end of input.

Yes, thanks. Not the right example to have picked! With your other
string function, the idea holds. Allow the user to choose if they
want to treat the return of NULL as a fatal error.

--
Ben.

Richard

unread,
Jan 28, 2008, 12:59:12 PM1/28/08
to
Randy Howard <randy...@FOOverizonBAR.net> writes:

> On Sun, 27 Jan 2008 21:01:40 -0600, Yevgen Muntyan wrote
> (in article <oAbnj.6924$fs4.3455@trnddc02>):
>> I don't like smart arses who know nothing except how to use
>> word "idiot" and its derivatives.
>
> When you refer to someone that holds a different opinion than you do as
> a "smart arse who knows nothing", how is that any better than calling
> someone an "idiot"? I'm curious how you arrived at this distinction,
> as well as how you determined what they don't know from afar.

It should be blatantly obvious. He is reacting as anyone would. People
who do waffle on about things they don't know and bandy the word "idiot"
about are indeed smart arses who know nothing most of the time. It's
quite clear.

>
>> Not that glib needs to be
>> defended of course, since it's something that actually works
>> in real world, not like those smarties' smart ideas.
>
> That people have written and deployed applications with glib doesn't
> mean that its design is good, or bad on its own. All it means is
> somebody typed 'make' and hit the enter key and out popped a binary
> which people use.

Erm, and it is a practical and USED solution for many, many top
applications. It works.

Richard

unread,
Jan 28, 2008, 1:00:28 PM1/28/08
to
Yevgen Muntyan <mun...@removethis.tamu.edu> writes:

> Kelsey Bjarnason wrote:


>> On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
>>
>>> Malcolm McLean wrote:
>>>> Here are six functions implemented on top of xmalloc(). No C programmer
>>>> should have any triouble providing the implemetations, though replace
>>>> and getquote are non-trivial.

>>> [snip]
>>>
>>>> I've think we've got something quite powerful here, purely because none
>>>> of these functions can ever return null for out of memory conditions.
>>>> It massively simplifies string handling.
>>> Take a look at glib,
>>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>>
>> Oh, good God. They didn't. Tell me they didn't.


>>
>> One wonders how many applications they've screwed over with that bit
>> of asinine idiocy.
>

> One wonders why one wonders about that only after he learns about
> g_malloc. Perhaps because those applications aren't actually screwed?

Precisely, but welcome to c.l.c

Paul Hsieh

unread,
Jan 28, 2008, 1:58:05 PM1/28/08
to
On Jan 27, 6:57 am, "Malcolm McLean" <regniz...@btinternet.com> wrote:
> Here are six functions implemented on top of xmalloc(). No C programmer
> should have any triouble providing the implemetations, though replace and
> getquote are non-trivial.
>
> char *dup(const char *str);
> char *cat(const char *str1, const char *str2);
> char *catandkill(char *str1, const char *str2);
> char *tok(const char *str, const char *delims, char **end);
> char *midstr(const char *str, int idx, int len);
> char *replace(const char *str, const char *pattern, const char *rep);
> char *getquote(const char *str, char quote, char escape, char **end);
> char *getline(FILE *fp);
>
> All return strings allocated with xmalloc().
>
> dup() is strdup(), and duplicates a string. cat() concatenates two strings.
> catandkill concatenagtes two strings, and frees the first. It also returns
> dup(str2) is the first pointer is null. It is designed for building strings
> in conveneint loops.
> tok() is strtok() that takes a string argument instead of using a global.
> midstr() takes out a central portion of the string. replace() is a find and
> replace, getquote() retrives the next quoted string, allowing for the quotes
> themselves to be escaped. You will have to escape non-quote escaped
> characters manually, of course. getline() will be a familiar friend.

>
> I've think we've got something quite powerful here, purely because none of
> these functions can ever return null for out of memory conditions. It
> massively simplifies string handling.

I'm curious as to why you think this simplifies string handling. If,
instead, you simply create an API for strings which *accepts* NULL as
a usable string, but treats it as a handled error then haven't you
achieved the same level of power and simplicity? Consider the
following macros:

#define stroffset(str,off) ((str)?(str)+off:NULL)
#define strcharat(str,off) ((str)?(str)[off]:EOF)

Now you have replacements for pointer arithmetic and even
dereferencing that can accept NULL pointers without crashing, but
which also continue to carry along the "state of error" so that errors
are not hidden. The point of this is to allow returning NULL on out
of memory conditions, while not suffering from accidental NULL pointer
dereferencing.

One thing you can point out to your detractors here in this thread is
that they fail to make this point, and thus fail to see value in
simplifying error handling. Indeed you do simplify error handling
with your solution, but the objections raised so far are asserting
that this is some sort of trade off in which they claim "call site
error handling is just better". They do this rather than pointing out
(as I do here) that its actually possible to eat your cake and have it
too and even with an API such as the one you've created so long as you
accept the following proviso that you make:

> The library is not terribly efficient and doesn't pretend to be.

But this was just one reason why my library didn't go this route. I
felt it was important to build a library for which there was no
reasonable objection to using it.

> [...] If you are
> doing heavy string processing you might want to look at Paul Hsieh's better
> string library, that stores a length parameter with strings.

Indeed. But I make a stronger assertion than that. Any string
processing that you can imagine is faster, easier, safer, more
maintainable and shorter using the Better String Library than using
the C library or nearly any other alternative that I have come across
(the major exception being that single threaded large string
manipulation will commonly be faster using James Antil's Vstr
library).

I don't abort on failure to allocate as you do, but using my library
you still enjoy substantially simplified error handling by way of
propagating errors in an accumulative way. So you do all your work,
capture the outputs and then check them all at the very end, and if
you didn't get full success, just destroy everything and perform
whatever error policy you like from the call site. This is a lot
easier than performing correct clean-up from the inside of a deeply
nested function in reaction to each error one at a time.

> [...] It is meant to be a few simple functions for easy manipulation.

The Better String Library started life, just as your list above, as a
very small library intent on delivering a powerful idea in a much
safer package. The apparent intimidating size of it these days has
come as a result of a lot of feedback and usage over the years. But
it has a fairly logical structure, and the core functions are easy
enough to understand. Nobody says you have to use it all, and its
unlikely that you would anyways.

I don't object to your making your own set of string routines,
especially if your purpose is to research your alternative approach.
But if your intention, knowing that my library exists, is to just
deliver simplified or otherwise improved string manipulation ... well
you should be aware that I have set the bar fairly high.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Flash Gordon

unread,
Jan 28, 2008, 2:39:23 PM1/28/08
to
Yevgen Muntyan wrote, On 28/01/08 04:17:
> William Ahern wrote:
>> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
>> <snip>
>>> This is very very wrong. A typical GUI application does not do a
>>> switch like
>>
>>> switch (problem_to_handle)
>>> {
>>> ...
>>> }
>>
>>> to which you could add
>>
>>> case ALLOC_FAILED:
>>
>>> It's usually different, you got the main loop which
>>> got to spin, you got those controls you got to draw,
>>> and you got those callbacks which actually do the
>>> job. And the callbacks do one thing at a time, they
>>> do not handle dozens of exceptional conditions at once,
>>> they do not handle exceptional conditions at all
>>> in fact.
>>
>> Is that why applications crash when, using a file dialog box, I
>> attempt to
>> save a file into a directory I don't have write permission to?
>
> No idea, ask the developers of that buggy application.
> Failed fopen() is not an exceptional condition. Failed
> malloc() is. Or we are using different vocabularies.

The point is that they both require similar recovery strategies.

>> To my mind, there's no difference in effort required to handle a NULL
>> return
>> from fopen(), than a NULL return from malloc(). Maybe more typing.
>
>
> Then you are just really good. Because it's enormously more
> typing.

Not necessarily.

> And more than that, it's more design questions too:
> "what do I do in this situation,

That is part of the normal design process.

> which I can't even possibly
> test?"

I can test it relatively easily. For example, I can use a malloc wrapper
which allows me to force a return of a null pointer when I want during
testing. Or I can use the debugger to put a breakpoint in and change the
pointer value to null at the point I want to trigger the failure.

> All this apart from real problems you have to solve.

Yes, this is called software design, a task that people writing software
should perform.

> Yes, *real*. No, g_malloc() aborting an application is not
> a real problem. Not for a regular desktop application.

You have just had pointed out to you a time when it has been a problem
for a user. I've previously pointed out times when applications have
given me a chance to recover the situation and it has avoided me loosing
a lot of work.

>> This is
>> just a resource acquisition issue, and even if you had infinite memory
>> it's
>> a pattern you still have to deal with.
>
> Except you don't open files twenty times in a row in every function
> in your application. Memory is quite a different kind of resource.
> Different in how you use it, you know.

I'm sure that William does know.

>> As to main loops, I'm very familiar with these. I write event based
>> async-io
>> network software, using an event dispatcher exactly like a GUI
>> application
>> might. I create and use more callback interfaces than I probably should.
>> When I accept a connection, I might--though, try not to--do dozens of
>> allocations. I try to write my code so any allocation failure is handled
>> gracefully. I don't need a gigantic switch statement, or special language
>> constructs. One designs the code to deal with such a circumstances as a
>> matter of course. You minimize dependencies, isolate access to shared
>> data,
>> postpone commiting to a particular state wrt to that context until you've
>> acquired a minimal set of resources, etc. Any non-trivial application
>> usually has multiple contexts within which such intermediate failures
>> can be
>> contained, with practical benefit.
>>
>> Granted, I've not done much work with X11 applications, or GUI
>> applications
>> in general. But, I fail to understand how a caveat wrt to X11
>> justifies--absent other reasons--exiting when a string cannot be
>> allocated.
>
> So you click Save button then click Close. The application failed to
> process Save click because it failed to allocate memory for the event
> structure to put into the event queue, but then it successfully handled
> Close because at the same time yet another document was closed and
> some memory returned to the malloc pool.

Do you have reason to believe that the X server is that brain dead? It
is an easy problem to handle by allocating the space in advance so that
when you get the event you *already* have the space to store it.

> You may not just lose events
> like that. *Everything* must be done in order, or the application is
> doomed, and the best it can do is to try to exit as nicely as it can
> (like save data or whatever). It can't just pretend nothing happened.

William has suggested *not* pretending nothing happened.

>>>> And yet out of all of
>>>> them people will argue memory allocation alone can be completely
>>>> ignored,
>>>> simply because it's too burdensome.
>> <snip>
>>> Of course I am talking about "small" allocations here, not
>>> about stuff like allocating memory to load an image file (for
>>> those g_malloc() is simply not used).
>>
>> There's absolutely no qualitative difference between small and large
>> allocations without reference to other circumstances (number of
>> allocations,
>> etc). If I have 4GB of memory, what does it matter that a 10MB
>> allocation is
>> checked but not a 12B allocation? When the application approaches the
>> limit
>> its not likely that one will be more susceptible to failure than the
>> other.
>> The choice is then arbitrary and almost absurd. Better, for
>> consistency, to
>> not bother at all.
>
> All allocations are checked. It's what you do when they fail is
> different. If malloc(12) failed, then you are screwed because
> all your code wants memory.

Not necessarily. For example, if you have done your job correctly the
*recovery* code already has the memory it needs allocated, so that can
run successfully.

> No memory => application isn't working.

Only if you don't design a suitable recovery process.

> So you just don't try to handle (that is do something and not exit
> the application) possible malloc() failure when you are concatenating
> two strings to make up a string to display. Absurd, fine, I'll be
> delighted to see an application which handles malloc() failure
> when it draws a menu label (it *is* possible, it just doesn't
> make sense).

I've had windows programs pop up message boxes telling me that they did
not have enough memory to open the window I asked them to open. It is
possibly, it just requires designing the software to handle the problem.
--
Flash Gordon

Flash Gordon

unread,
Jan 28, 2008, 3:02:51 PM1/28/08
to
Malcolm McLean wrote, On 28/01/08 09:21:

<snip>

> int main(int argc, char **argv)
> {
> FILE *fp;
> char *line;
> int i = 1;

int error_flag = 0;

>
> if(argc != 2)
> exit(EXIT_FAILURE);
> fp = fopen(argv[1], "r");
> if(!fp)
> {
> fprintf(stderr, "Can't open %s\n", argv[1]);
> exit(EXIT_FAILURE);
> }
> while(line = getline(fp))

Replace with
while (line = getline(fp,&error_flag))

> {
> printf("%d: %s", i++, line);
> free(line);
> }

if (error_flag == NO_MEMORY)
fprintf(stderr,"Program ran out of memory reading line %d\n",i);

> fclose(fp);
> return 0;
> }
>
> There's a program to print a file, prepending the line number. See how
> simple it is, because we don't have to do any error processing?

See, three lines added and one changed and now it will report the error
in a much more useful way.

Of course, the entire application should have been written differently
so that it does not repeatedly allocate and free memory.
--
Flash Gordon

Kelsey Bjarnason

unread,
Jan 28, 2008, 9:47:07 AM1/28/08
to
On Sun, 27 Jan 2008 23:56:11 +0000, Yevgen Muntyan wrote:

> Kelsey Bjarnason wrote:
>> On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
>>

>>> Malcolm McLean wrote:
>>>> Here are six functions implemented on top of xmalloc(). No C
>>>> programmer should have any triouble providing the implemetations,
>>>> though replace and getquote are non-trivial.

>>> [snip]


>>>
>>>> I've think we've got something quite powerful here, purely because
>>>> none of these functions can ever return null for out of memory
>>>> conditions. It massively simplifies string handling.

>>> Take a look at glib,
>>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>>
>> Oh, good God. They didn't. Tell me they didn't.
>>
>> One wonders how many applications they've screwed over with that bit of
>> asinine idiocy.
>
> One wonders why one wonders about that only after he learns about
> g_malloc. Perhaps because those applications aren't actually screwed?

Really? What's their recovery mechanism on allocation failure, then?

Oh, right... allocations never fail. Just ask Malcolm.

Kelsey Bjarnason

unread,
Jan 28, 2008, 9:57:04 AM1/28/08
to
[snips]

On Mon, 28 Jan 2008 03:16:22 +0000, Randy Howard wrote:

>> I don't like smart arses who know nothing except how to use word
>> "idiot" and its derivatives.

> When you refer to someone that holds a different opinion than you do as
> a "smart arse who knows nothing", how is that any better than calling
> someone an "idiot"? I'm curious how you arrived at this distinction, as
> well as how you determined what they don't know from afar.

Indeed. Also how he seems to be incapable of distinguishing between
calling a particular design decision "idiocy" and calling the person(s)
involved "idiot". Like we don't _all_ have brain farts and do stupid
things on occasion.

> That people have written and deployed applications with glib doesn't
> mean that its design is good, or bad on its own. All it means is
> somebody typed 'make' and hit the enter key and out popped a binary
> which people use.

Indeed, and the fact it uses this strategy on allocation failure is a
pretty strong argument that it is _not_ a good design. It may be
absolutely fantastic in 17,000 other ways, but this one is about as bad
as it gets.

dj3v...@csclub.uwaterloo.ca.invalid

unread,
Jan 28, 2008, 6:22:54 PM1/28/08
to
In article <mplu65-...@spanky.localhost.net>,

Kelsey Bjarnason <kbjar...@gmail.com> wrote:
>On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:

>> Take a look at glib,
>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>
>Oh, good God. They didn't. Tell me they didn't.

Well, this *is* the same project whose documentation claims that size_t
didn't exist until C99, so somehow it wouldn't surprise me. There's
nothing like an obvious lack of *any* *basic* caring about correctness
(never mind the fanatical devotion to it that's needed to do things
properly) to inspire a spectacular lack of confidence in a software
project.


dave

--
Dave Vandervies dj3vande at eskimo dot com
Effectively, Microsoft creates good programming the same way that sand
grains create pearls - through irritating someone else. And Microsoft has
a lot of sand. --SteveD in the scary devil monastery

ymun...@gmail.com

unread,
Jan 28, 2008, 6:30:50 PM1/28/08
to
On Jan 28, 1:39 pm, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> Yevgen Muntyan wrote, On 28/01/08 04:17:
>
>
>
> > William Ahern wrote:
> >> Yevgen Muntyan <munt...@removethis.tamu.edu> wrote:
> >> <snip>
> >>> This is very very wrong. A typical GUI application does not do a
> >>> switch like
>
> >>> switch (problem_to_handle)
> >>> {
> >>> ...
> >>> }
>
> >>> to which you could add
>
> >>> case ALLOC_FAILED:
>
> >>> It's usually different, you got the main loop which
> >>> got to spin, you got those controls you got to draw,
> >>> and you got those callbacks which actually do the
> >>> job. And the callbacks do one thing at a time, they
> >>> do not handle dozens of exceptional conditions at once,
> >>> they do not handle exceptional conditions at all
> >>> in fact.
>
> >> Is that why applications crash when, using a file dialog box, I
> >> attempt to
> >> save a file into a directory I don't have write permission to?
>
> > No idea, ask the developers of that buggy application.
> > Failed fopen() is not an exceptional condition. Failed
> > malloc() is. Or we are using different vocabularies.
>
> The point is that they both require similar recovery strategies.


The point is that they don't. If fopen() fails, there is nothing
to recover from. Though if all your application does is fopen(),
then you can safely abort() when fopen() fails.


> >> To my mind, there's no difference in effort required to handle a NULL
> >> return
> >> from fopen(), than a NULL return from malloc(). Maybe more typing.
>
> > Then you are just really good. Because it's enormously more
> > typing.
>
> Not necessarily.

So, you work with a list, and you append an element to it.
Now you do list = g_list_append(list, something); with malloc
error handling you'll have to test whether list_append()
succeeded. Not much more typing, no. A little bit more, huh?
C++ exceptions would be appropriate here, but manual error
checking in C code *is* much much more typing.

>
> > And more than that, it's more design questions too:
> > "what do I do in this situation,
>
> That is part of the normal design process.
>
> > which I can't even possibly
> > test?"
>
> I can test it relatively easily. For example, I can use a malloc wrapper
> which allows me to force a return of a null pointer when I want during
> testing. Or I can use the debugger to put a breakpoint in and change the
> pointer value to null at the point I want to trigger the failure.

There are about five bazillion allocations, debugger won't do. Random
malloc() failures will do as a nice stress test, yes. But you still
won't be able to test it properly. At least not that piece of code
where it will segfault when user runs it (here I assume that user
will be able to see it, perhaps on windows). A better thing to do
is to test malloc() failure in one place, and possibly do what you
can do there, and abort.

>
> > All this apart from real problems you have to solve.
>
> Yes, this is called software design, a task that people writing software
> should perform.
>
> > Yes, *real*. No, g_malloc() aborting an application is not
> > a real problem. Not for a regular desktop application.
>
> You have just had pointed out to you a time when it has been a problem
> for a user.

Yeah, mozilla leaking too much. Or evolution leaking too much (?).
It would be nice to see something more substantial than "I know
for a fact" (debugged it, looked at the core file?). And would
be nice to hear about gedit or gnumeric crashing because of malloc()
failure.

> I've previously pointed out times when applications have
> given me a chance to recover the situation and it has avoided me loosing
> a lot of work.

Avoiding losing your work in an emergency condition is just
a different story, say you can have your application lost its
terminal or X connection, in those cases you can possibly do
something to save user's work. And that's something you can
(try to) do from inside g_malloc() when malloc() fails. It's
not necessary to write a g_list_append() which can fail for
that.

Yes I actually do (try xorg sources). But it's not quite relevant,
since I wasn't talking about X server. Though if X server dies then
Xlib will kill the application too.

> It
> is an easy problem to handle by allocating the space in advance so that
> when you get the event you *already* have the space to store it.

So, you got an event, you need to put it into the event queue.
Either you allocate memory for that (and it fails), or you
preallocate memory, it is not enough, and you try to allocate
again (and it fails). What can you do apart from some emergency
action (saving important data or something) and exit? How
do you "recover"?

>
> > You may not just lose events
> > like that. *Everything* must be done in order, or the application is
> > doomed, and the best it can do is to try to exit as nicely as it can
> > (like save data or whatever). It can't just pretend nothing happened.
>
> William has suggested *not* pretending nothing happened.


Right, he didn't suggest anything.

Recovery code will be able to run successfully, so what?
The rest of the code still wants memory.

>
> > No memory => application isn't working.
>
> Only if you don't design a suitable recovery process.

Again, no recovery process will be able to make your main loop
spin happily again. The recovery process can't get memory from
nowhere (unless by recovery you mean killing parts of application,
in which case it again doesn't make sense to proceed in normal way).

>
> > So you just don't try to handle (that is do something and not exit
> > the application) possible malloc() failure when you are concatenating
> > two strings to make up a string to display. Absurd, fine, I'll be
> > delighted to see an application which handles malloc() failure
> > when it draws a menu label (it *is* possible, it just doesn't
> > make sense).
>
> I've had windows programs pop up message boxes telling me that they did
> not have enough memory to open the window I asked them to open. It is
> possibly, it just requires designing the software to handle the problem.

Perhaps. Except it's not "just". Again, I'll be delighted to see an
application which handles malloc() failure when it draws a menu label.
Preferably its code, to learn from. Oh, and see the code which works
with list allocated on heap, which handles every possible failure of
list_append() (no exceptions and alike please, don't we agree that
all we need is 'if (failed()) recover()'?).

Yevgen

Kelsey Bjarnason

unread,
Jan 28, 2008, 10:27:42 AM1/28/08
to
[snips]

On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:

> No idea, ask the developers of that buggy application. Failed fopen() is
> not an exceptional condition. Failed malloc() is. Or we are using
> different vocabularies.

Apparently so. To me, they are both error conditions, to be handled
appropriately - by the caller. Neither is exceptional.

>> To my mind, there's no difference in effort required to handle a NULL
>> return from fopen(), than a NULL return from malloc(). Maybe more
>> typing.

> Then you are just really good. Because it's enormously more typing.

if ( ( file = fopen(...) ) == NULL ) {}
if ( ( ptr = malloc(...) ) == NULL ) {}

Yeah, enormously more, indeed.

> And
> more than that, it's more design questions too: "what do I do in this

> situation, which I can't even possibly test?"

Can't test? Why can't you test an allocation failure? I do it all the
time. It's pretty trivial, actually, if you're using a language which
includes constructs such as if ( condition ) action. You know, like,
say, C.

> All this apart from real

> problems you have to solve. Yes, *real*. No, g_malloc() aborting an


> application is not a real problem. Not for a regular desktop
> application.

Except that at least one person *here*, in a comparatively small
community, has reported application crashes *precisely* due to this.

I wish I knew where this notion of "Hey, it's just an application, feel
free to kill it because it's 3:00, or the sky is blue, or whatever other
random event has occurred" has come from. I've been cranking apps for
most of 30 years now, and I have *never* found it acceptable for an
application to simply terminate, unless there is absolutely no other
possible option.

>> This is
>> just a resource acquisition issue, and even if you had infinite memory
>> it's a pattern you still have to deal with.
>
> Except you don't open files twenty times in a row in every function in
> your application. Memory is quite a different kind of resource.
> Different in how you use it, you know.

Different how? Files or memory, each needs to be requested before use,
each can fail on request, each needs to have the request failure dealt
with. If the request is successful, the resource is used then disposed
of by appropriate means.

In terms *relevant to the topic*, there is no difference at all.
Request, cope with possible request failure, use, dispose.

>> Granted, I've not done much work with X11 applications, or GUI
>> applications in general. But, I fail to understand how a caveat wrt to
>> X11 justifies--absent other reasons--exiting when a string cannot be
>> allocated.

> So you click Save button then click Close. The application failed to
> process Save click because it failed to allocate memory for the event
> structure to put into the event queue, but then it successfully handled
> Close because at the same time yet another document was closed and some
> memory returned to the malloc pool.

That strikes me as a design flaw in the application. If the user
requested "save and close" and the save failed, what the hell are you
doing processing the close, instead of dealing with the error?

This would be particularly bad since the failure to save was *not*
because a file couldn't be written to, but because a menu event couldn't
be put in a message queue. If you must process the close, at least have
the decency to save the data, possibly in a scratch file which can be
recovered next time around.

Yes, certainly, at some point the options run out. If you can't allocate
space for a message on the queue, you probably also can't allocate
resources for a warning dialog. If you can't create a scratch file *and*
you can't allocate resources for the warning, there may be little you can
do but abort.

That, however, does not excuse the whole notion of "Hey, first thing we
tried failed, so let's just abort."

> All allocations are checked. It's what you do when they fail is
> different. If malloc(12) failed, then you are screwed because all your
> code wants memory.

No, you're not screwed. You have a possible failure condition to deal
with, one which might be an expected condition, one which might not be,
and in either case, there are many possible resolutions to the problem.

> No memory => application isn't working.

Or application isn't working optimally. Or _this part_ of the
application isn't working _now_, so try again in five minutes. Or...

ymun...@gmail.com

unread,
Jan 28, 2008, 6:53:59 PM1/28/08
to
On Jan 28, 9:27 am, Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
> [snips]
>
> On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
> > No idea, ask the developers of that buggy application. Failed fopen() is
> > not an exceptional condition. Failed malloc() is. Or we are using
> > different vocabularies.
>
> Apparently so. To me, they are both error conditions, to be handled
> appropriately - by the caller. Neither is exceptional.
>
> >> To my mind, there's no difference in effort required to handle a NULL
> >> return from fopen(), than a NULL return from malloc(). Maybe more
> >> typing.
> > Then you are just really good. Because it's enormously more typing.
>
> if ( ( file = fopen(...) ) == NULL ) {}
> if ( ( ptr = malloc(...) ) == NULL ) {}
>
> Yeah, enormously more, indeed.

I love how everybody pushes such toy code. You forgot
the part inside {}, you know.

>
> > And
> > more than that, it's more design questions too: "what do I do in this
> > situation, which I can't even possibly test?"
>
> Can't test? Why can't you test an allocation failure? I do it all the
> time. It's pretty trivial, actually, if you're using a language which
> includes constructs such as if ( condition ) action. You know, like,
> say, C.

Not test as in 'if(something)'. Test as in "run the program and
see what happens when that allocation fails".

>
> > All this apart from real
> > problems you have to solve. Yes, *real*. No, g_malloc() aborting an
> > application is not a real problem. Not for a regular desktop
> > application.
>
> Except that at least one person *here*, in a comparatively small
> community, has reported application crashes *precisely* due to this.

He did, didn't he.

>
> I wish I knew where this notion of "Hey, it's just an application, feel
> free to kill it because it's 3:00, or the sky is blue, or whatever other
> random event has occurred" has come from. I've been cranking apps for
> most of 30 years now, and I have *never* found it acceptable for an
> application to simply terminate, unless there is absolutely no other
> possible option.
>
> >> This is
> >> just a resource acquisition issue, and even if you had infinite memory
> >> it's a pattern you still have to deal with.
>
> > Except you don't open files twenty times in a row in every function in
> > your application. Memory is quite a different kind of resource.
> > Different in how you use it, you know.
>
> Different how? Files or memory, each needs to be requested before use,
> each can fail on request, each needs to have the request failure dealt
> with. If the request is successful, the resource is used then disposed
> of by appropriate means.
>
> In terms *relevant to the topic*, there is no difference at all.
> Request, cope with possible request failure, use, dispose.

Yeah. Stack space is also such a resource. Do you always use whatever
your implementation provides to cope with stack allocation failure?
Just curious.

>
> >> Granted, I've not done much work with X11 applications, or GUI
> >> applications in general. But, I fail to understand how a caveat wrt to
> >> X11 justifies--absent other reasons--exiting when a string cannot be
> >> allocated.
> > So you click Save button then click Close. The application failed to
> > process Save click because it failed to allocate memory for the event
> > structure to put into the event queue, but then it successfully handled
> > Close because at the same time yet another document was closed and some
> > memory returned to the malloc pool.
>
> That strikes me as a design flaw in the application. If the user
> requested "save and close" and the save failed, what the hell are you
> doing processing the close, instead of dealing with the error?

The application has no idea that user clicked "Save" in this case.
So it didn't fail to save. The very event was dropped and forgotten.
Of course it's a made up example, no need to talk about design here.
A more realistic one is:

void the_toolkit_event_function (Event *event)
{
event_queue = g_list_prepend (event_queue, copy (event));
}

What do you do there if g_list_prepend fails because it failed
to allocate space for the list link? You just can't drop the
event, because that could lead to funny things like ignoring
user requests (or worse, X is funny like that).

> This would be particularly bad since the failure to save was *not*
> because a file couldn't be written to, but because a menu event couldn't
> be put in a message queue. If you must process the close, at least have
> the decency to save the data, possibly in a scratch file which can be
> recovered next time around.
>
> Yes, certainly, at some point the options run out. If you can't allocate
> space for a message on the queue, you probably also can't allocate
> resources for a warning dialog. If you can't create a scratch file *and*
> you can't allocate resources for the warning, there may be little you can
> do but abort.
>
> That, however, does not excuse the whole notion of "Hey, first thing we
> tried failed, so let's just abort."

Nobody said this, you can do stuff on malloc() failure.
But even without that, this whole notion is very useful
in applications where it's acceptable. I won't care much
if my mp3 player crashes when my X display is frozen anyway.
You can handle malloc() failures how much you want there,
and it will be pointless.

>
> > All allocations are checked. It's what you do when they fail is
> > different. If malloc(12) failed, then you are screwed because all your
> > code wants memory.
>
> No, you're not screwed. You have a possible failure condition to deal
> with, one which might be an expected condition, one which might not be,
> and in either case, there are many possible resolutions to the problem.

Indeed. And you make these decisions thousands times in your code,
and you test every one, and every one is exactly the best and right.
And there is a peace in the world, and so on.

>
> > No memory => application isn't working.
>
> Or application isn't working optimally. Or _this part_ of the
> application isn't working _now_, so try again in five minutes. Or...

... is especially good when you are writing code. I believe the
first choice is better.

Yevgen

Kelsey Bjarnason

unread,
Jan 28, 2008, 11:11:30 AM1/28/08
to
On Sun, 27 Jan 2008 23:54:01 +0000, Yevgen Muntyan wrote:

> Randy Howard wrote:
>> On Sun, 27 Jan 2008 16:12:01 -0600, William Ahern wrote (in article
>> <h6cv65-...@wilbur.25thandClement.com>):


>>
>>> Yevgen Muntyan <mun...@removethis.tamu.edu> wrote:
>>>> Malcolm McLean wrote:
>>>>> Here are six functions implemented on top of xmalloc(). No C
>>>>> programmer should have any triouble providing the implemetations,
>>>>> though replace and getquote are non-trivial.
>>>> [snip]
>>>>> I've think we've got something quite powerful here, purely because
>>>>> none of these functions can ever return null for out of memory
>>>>> conditions. It massively simplifies string handling.

>>> glib is where bad ideas go to die. Now, if somebody just had the nerve
>>> to tell them....
>>
>> :)
>>
>> You gdon't glike ghaving gall gyour gvariables gprexfed gwith g?
>
> Why, you don't like the following code?
>
> #include <glib.h>
>
> gint main (gint argc, gchar **argv)
> {
> gchar *s = g_strdup ("Hello there!"); g_print ("%s\n", s);
> g_free (s);
> }


G_no, g_I g_don't.

Kelsey Bjarnason

unread,
Jan 28, 2008, 11:25:01 AM1/28/08
to
On Mon, 28 Jan 2008 23:22:54 +0000, dj3vande wrote:

> In article <mplu65-...@spanky.localhost.net>, Kelsey Bjarnason
> <kbjar...@gmail.com> wrote:
>>On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
>
>>> Take a look at glib,
>>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
>>
>>Oh, good God. They didn't. Tell me they didn't.
>
> Well, this *is* the same project whose documentation claims that size_t
> didn't exist until C99, so somehow it wouldn't surprise me. There's
> nothing like an obvious lack of *any* *basic* caring about correctness
> (never mind the fanatical devotion to it that's needed to do things
> properly) to inspire a spectacular lack of confidence in a software
> project.

Yeah, well, Gnome has always brought out the "ick factor" in me, though I
never really knew why. Properly speaking, I still don't, but at least
now there's some objective basis to write the whole thing off as being
nothing but a reaction to last night's iffy pork moo shu.

size_t didn't exist until C99. They didn't really say that, did they?

Richard Heathfield

unread,
Jan 28, 2008, 7:36:37 PM1/28/08
to
Kelsey Bjarnason said:

> [snips]
>
> On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
>

<snip>



>> All this apart from real
>> problems you have to solve. Yes, *real*. No, g_malloc() aborting an
>> application is not a real problem. Not for a regular desktop
>> application.
>
> Except that at least one person *here*, in a comparatively small
> community, has reported application crashes *precisely* due to this.

Yes, Kelsey, but so what? Read what he's saying: this is *not* a real
problem. It's only data - how could mere data possibly be important enough
to justify spending a little extra time working out how to salvage it in
the event of an allocation failure?

> I wish I knew where this notion of "Hey, it's just an application, feel
> free to kill it because it's 3:00, or the sky is blue, or whatever other
> random event has occurred" has come from. I've been cranking apps for
> most of 30 years now, and I have *never* found it acceptable for an
> application to simply terminate, unless there is absolutely no other
> possible option.

You're a dinosaur who has failed to adapt to the Postmodernist school of
programming, where anything goes, any old garbage is acceptable, users are
worth nothing, and their data is worth rather less than nothing. Forget
best software engineering practice, because it's old hat nowadays - if you
want robustness, buy a Volvo.

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

dj3v...@csclub.uwaterloo.ca.invalid

unread,
Jan 28, 2008, 7:42:21 PM1/28/08
to
In article <t7c175-...@spanky.localhost.net>,

If you're in a generous mood, it's possible to read it in a way that
introduces some uncertainty about whether they're really saying that.
But it certainly looks to me like that's what they're saying.

<http://library.gnome.org/devel/glib/2.14/glib-Basic-Types.html#id2913732>:
--------
GLib defines a number of commonly used types, which can be divided into
4 groups:
* New types which are not part of standard C - gboolean, gsize,
gssize.
--------

Same page, near the bottom (at glib-Basic-Types.html#gsize):
--------
gsize

typedef unsigned int gsize;

An unsigned integer type of the result of the sizeof operator,
corresponding to the size_t type defined in C99. This type is wide
enough to hold the numeric value of a pointer, so it is usually 32bit
wide on a 32bit platform and 64bit wide on a 64bit platform.
--------
I wonder what happens on an il32p64 system? Is the typedef accurate,
or is the description? Do they check for that? Do they care?
Earlier versions of the documentation specifically documented it as a
32-bit unsigned integer type. I wonder how many people that assumption
is going to bite during the transition to 64 bits?
(I can ignore the assumption of a flat memory space for now, since that
one might take a bit longer to swing back the other way. Not that that
means anything other than "it'll be even more painful when it happens"
in the long run.)


ObC: Use the standard types (size_t in this case) for this kind of
thing. That's What They're There For. The compiler knows better than
you do, ESPECIALLY if you're writing a library for other people to
use.

William Ahern

unread,
Jan 28, 2008, 7:53:18 PM1/28/08
to
Kelsey Bjarnason <kbjar...@gmail.com> wrote:
> On Mon, 28 Jan 2008 23:22:54 +0000, dj3vande wrote:

> > In article <mplu65-...@spanky.localhost.net>, Kelsey Bjarnason
> > <kbjar...@gmail.com> wrote:
> >>On Sun, 27 Jan 2008 20:34:58 +0000, Yevgen Muntyan wrote:
> >
> >>> Take a look at glib,
> >>> http://library.gnome.org/devel/glib/2.14/glib-Memory-Allocation.html
> >>
> >>Oh, good God. They didn't. Tell me they didn't.
> >
> > Well, this *is* the same project whose documentation claims that size_t
> > didn't exist until C99, so somehow it wouldn't surprise me. There's
> > nothing like an obvious lack of *any* *basic* caring about correctness
> > (never mind the fanatical devotion to it that's needed to do things
> > properly) to inspire a spectacular lack of confidence in a software
> > project.

> Yeah, well, Gnome has always brought out the "ick factor" in me, though I
> never really knew why. Properly speaking, I still don't, but at least
> now there's some objective basis to write the whole thing off as being
> nothing but a reaction to last night's iffy pork moo shu.

You shouldn't equate glib with GNOME. Miguel de Icaza and some others have
opined that C is an inadequate tool for what they wish to accomplish on the
desktop. Mono was started in part for this very reason.

OTOH, maybe you can. I'm not sure how many people have followed Miguel's
lead. And glib seems, anecdotally, to have become more pervasive in Gtk+ and
GNOME apps.

Kelsey Bjarnason

unread,
Jan 28, 2008, 12:11:55 PM1/28/08
to
[snips]

On Mon, 28 Jan 2008 15:53:59 -0800, ymuntyan wrote:

>> >> To my mind, there's no difference in effort required to handle a
>> >> NULL return from fopen(), than a NULL return from malloc(). Maybe
>> >> more typing.
>> > Then you are just really good. Because it's enormously more typing.
>>
>> if ( ( file = fopen(...) ) == NULL ) {} if ( ( ptr = malloc(...) ) ==
>> NULL ) {}
>>
>> Yeah, enormously more, indeed.
>
> I love how everybody pushes such toy code. You forgot the part inside
> {}, you know.

Yes, I did - in *both* cases. Why? Because there's simply not enough
information available to say whether the code in one would be simpler
than in the other, or what that code would be.

In some apps, allocation failure is a critical issue. In others, it's no
more than a minor inconvenience. In others, it's somewhere in between.
The same can be said in the case of file open failures.

Take, oh, a chess program. Can't open it's persistent hash file? Okay,
fine, so it plays a few points weaker than it would otherwise, this is
hardly fatal. Another app, failure to open the file may be fatal.

The absurd notion that just because it's an allocation failure, it is
magically transformed into a world-ending problem which far exceeds the
complexity of a file open problem is, well, absurd.

>> Can't test? Why can't you test an allocation failure? I do it all the
>> time. It's pretty trivial, actually, if you're using a language which
>> includes constructs such as if ( condition ) action. You know, like,
>> say, C.
>
> Not test as in 'if(something)'. Test as in "run the program and see what
> happens when that allocation fails".

Oh, well, that's pretty damn easy, too, in many cases. Depending on
environment and implementation, you could replace malloc with one of your
own, or a custom one which allows you to set how much memory to
allocate. You could limit the memory available to a process. The fact
it's an allocation hardly means it's impossible to test.

>> In terms *relevant to the topic*, there is no difference at all.
>> Request, cope with possible request failure, use, dispose.
>
> Yeah. Stack space is also such a resource. Do you always use whatever
> your implementation provides to cope with stack allocation failure? Just
> curious.

Er, not sure the point here. Last I checked, C had no mechanism
whatsoever to detect available stack space or detect stack failures, and
this is CLC, where we do C. As _C_ code, there is simply no way to
accomplish this task. As _C_ code, there _is_ a way to detect an
allocation failure.

So, how about you explain the strictly conforming methodology for
detecting stack space and detecting stack allocation failures, and we'll
examine whether or not they can be managed in the same sort of way.

Pedantic? Perhaps, but then the code cannot use any particular mechanism
to ensure that the power grid stays up, or that the guy being
communicated with halfway around the world is actually still at his desk,
or that the satellite used to carry the communication signal isn't
merrily falling to earth and about to explode.

These things _cannot_ be checked or handled in C; malloc failures _can_.
So how about we stick to C.

>> That strikes me as a design flaw in the application. If the user
>> requested "save and close" and the save failed, what the hell are you
>> doing processing the close, instead of dealing with the error?

> The application has no idea that user clicked "Save" in this case.

How can it _not_? What, was the menu put up there by magic?

> So it
> didn't fail to save. The very event was dropped and forgotten.

Okay, so it's a bogus UI design, is what you're saying. So, do we shoot
the application designer who designed the UI in such a manner, or is this
yet another glib issue?

> Of course
> it's a made up example, no need to talk about design here. A more
> realistic one is:
>
> void the_toolkit_event_function (Event *event) {
> event_queue = g_list_prepend (event_queue, copy (event));
> }
>
> What do you do there if g_list_prepend fails because it failed to
> allocate space for the list link? You just can't drop the event, because
> that could lead to funny things like ignoring user requests (or worse, X
> is funny like that).

Not sure, as I don't know what the event mechanism is, what the events
are, what the import is of the whole process. As for "allocate space for
the list link", not sure what that means, either, in that context. Do
you mean that copy() might fail? If so, the code, as written, is - IMO -
very poorly structured, as it makes no provision for copy failing, unless
g_list_prepend is smart enough to detect the NULL and respond back
appropriately, something I wouldn't bet on given the current discussion.

Nor does it tell me enough even if I know this is the case. For example,
it _may_ be perfectly acceptable to simply "spin the wheels" a while,
doing something else, until the copy can be performed. Or it may be
acceptable to simply "block" - wait until space is available. Or there
may be an error reporting mechanism available which allows one to report
and take some other appropriate action.

>> That, however, does not excuse the whole notion of "Hey, first thing we
>> tried failed, so let's just abort."
>
> Nobody said this, you can do stuff on malloc() failure.

Actually, that's pretty much the entire point to both the Malcolm and the
glib sides of the discussion; if allocation fails, abort the app. No ifs
ands or buts, it is allocate or die - which only makes sense if you
*cannot* do anything on allocation failure.

> But even without
> that, this whole notion is very useful in applications where it's
> acceptable. I won't care much if my mp3 player crashes when my X display
> is frozen anyway.

If X is frozen, then presumably the mp3 player, which I assume uses X for
a variety of things, is likely to be hosed itself. On the other hand,
perhaps it's not an X mp3 player, but, oh, something like mpg123. Unless
X's freezing is because of total systemic resource exhaustion, why should
an X issue have any impact on the app?

Then again, we're not talking about _X_ freezing here, we're talking
about the notion that an allocation failure means instant death. If my
mp3 app can't handle the size of my playlist - can't allocate space for
it - I expect it to do the sane thing and *tell* me so, not just puke and
die. That's sloppy programming of the worst sort, totally unacceptable,
even in something as trivial as an mp3 player, and absolutely fatal in a
more serious app.

>> No, you're not screwed. You have a possible failure condition to deal
>> with, one which might be an expected condition, one which might not be,
>> and in either case, there are many possible resolutions to the problem.
>
> Indeed. And you make these decisions thousands times in your code, and
> you test every one, and every one is exactly the best and right. And
> there is a peace in the world, and so on.

Correct. Well, apart from the peace in the world part. Yes, allocation
is followed by validation and handling of possible failure. It is not
difficult to do, programmers have been doing it since the invention of
languages with managed memory allocation.

>> > No memory => application isn't working.
>>
>> Or application isn't working optimally. Or _this part_ of the
>> application isn't working _now_, so try again in five minutes. Or...
>
> ... is especially good when you are writing code. I believe the first
> choice is better.

Better how? If the reason I'm allocating the buffer is to improve
performance, the fact I can't get one as large as I want doesn't mean the
program won't work, it simply means it will take a little longer.

Oh, wait, no, that's not right, can't have that, we *must* kill the app,
dead. Can't have anything less than optimal performance, obviously the
app must die.

ymun...@gmail.com

unread,
Jan 28, 2008, 8:29:17 PM1/28/08
to
On Jan 28, 6:42 pm, dj3va...@csclub.uwaterloo.ca.invalid wrote:
> In article <t7c175-399....@spanky.localhost.net>,

> Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
>
>
>
> >On Mon, 28 Jan 2008 23:22:54 +0000, dj3vande wrote:
>
> >> In article <mplu65-oei....@spanky.localhost.net>, Kelsey Bjarnason

So whoever wrote that thought size_t is new in C99. Care to file a
bug
report? You won't be able to quote a glib *developer* who claimed
size_t
is new in C99; and if you are pedantic enough, you won't even be able
to say that the quoted text is wrong. It does *not* say
"size_t didn't exist until C99".

> This type is wide
> enough to hold the numeric value of a pointer, so it is usually 32bit
> wide on a 32bit platform and 64bit wide on a 64bit platform.
> --------
> I wonder what happens on an il32p64 system?

gsize will be __int64 or long long if it's windows; in any
case the description will be accurate.

> Is the typedef accurate,

No, it's gotten from the code by the documentation tool. So it
is accurate on the platform where the docs were built, but not
on every platform (a docs bug, yes).

> or is the description? Do they check for that? Do they care?
> Earlier versions of the documentation specifically documented it as a
> 32-bit unsigned integer type. I wonder how many people that assumption
> is going to bite during the transition to 64 bits?

That transition happened long ago, and no, it's not the same
story as with win32 long. If someone was bitten by such an
assumption, then it's the same people who think that 'long' is
a '32-bit integer type'.

> (I can ignore the assumption of a flat memory space for now, since that
> one might take a bit longer to swing back the other way. Not that that
> means anything other than "it'll be even more painful when it happens"
> in the long run.)
>
> ObC: Use the standard types (size_t in this case) for this kind of
> thing. That's What They're There For. The compiler knows better than
> you do, ESPECIALLY if you're writing a library for other people to
> use.

I myself wonder why glib doesn't like standard headers. I suspect
it's so because of some historical reasons. Either way, gsize is
the same type as size_t on all platforms where glib runs. So while
it's not nice enough, it is working (as in "works right").

Yevgen

ymun...@gmail.com

unread,
Jan 28, 2008, 8:38:05 PM1/28/08
to
On Jan 28, 11:11 am, Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
> [snips]
>
> On Mon, 28 Jan 2008 15:53:59 -0800, ymuntyan wrote:

[snip]

> >> That, however, does not excuse the whole notion of "Hey, first thing we
> >> tried failed, so let's just abort."
>
> > Nobody said this, you can do stuff on malloc() failure.
>
> Actually, that's pretty much the entire point to both the Malcolm and the
> glib sides of the discussion; if allocation fails, abort the app. No ifs
> ands or buts, it is allocate or die - which only makes sense if you
> *cannot* do anything on allocation failure.

But it's not true, there are ifs and buts. Using glib, you *can*
do stuff when malloc() fails. Yes, using glib all you sensibly
can do on malloc() failure is some sort of emergency work and
quit. If your application requires more, then you don't want to
use glib, that's it. But I claim that for 'regular' desktop
applications that is quite enough.

Yevgen

Kelsey Bjarnason

unread,
Jan 28, 2008, 12:40:13 PM1/28/08
to
[snips]

On Mon, 28 Jan 2008 15:30:50 -0800, ymuntyan wrote:

>> > No idea, ask the developers of that buggy application. Failed fopen()
>> > is not an exceptional condition. Failed malloc() is. Or we are using
>> > different vocabularies.
>>
>> The point is that they both require similar recovery strategies.
>
>
> The point is that they don't. If fopen() fails, there is nothing to
> recover from.

If my fopen fails and I can't load my app's config file, I can't get the
preferred options. Depending on the app, this could be anything from a
minor annoyance to a critical failure. In every one of those cases,
there is something to recover from.

If my fopen fails because the user has no read permissions (or no write
permissions, if he's trying to open for write), there is something to
recover from - let him know he has no permissions, go back to the file
select dialog (or whatever called fopen) and let the user decide what to
do about it - choose a different file name, fix the permissions, whatever.

I'm sorry, but "there's nothing to recover from" is just so completely
out of touch with reality I can't believe you said it.

> So, you work with a list, and you append an element to it. Now you do
> list = g_list_append(list, something); with malloc error handling you'll
> have to test whether list_append() succeeded.

That depends entirely on how your list functions work. As a simple
example:

/* NODE and LIST are actually the same thing, just written differently
for clarity's sake */
void list_append( LIST *list, NODE *new )
{
NODE *node = list;

/* Find end of list */
while( node->next != NULL )
node = node->next;

/* Add item to end of list */
node->next = new;
new->next = NULL;
}

Sorry, what, exactly, did I need to check here with malloc error
handling? What's that you say, nothing at all, since there _is_ no
malloc involved in adding a node to the list? Ah, yes. Of course, we
need to allocate the node itself:

NODE *node;
LIST *list;

...

node = malloc( sizeof( *node ) );
if ( node == NULL )
{
blah
}
else
{
list_append( list, node );
blah
}

Golly, how unbearably painful.


>> I can test it relatively easily. For example, I can use a malloc
>> wrapper which allows me to force a return of a null pointer when I want
>> during testing. Or I can use the debugger to put a breakpoint in and
>> change the pointer value to null at the point I want to trigger the
>> failure.

> There are about five bazillion allocations, debugger won't do. Random
> malloc() failures will do as a nice stress test, yes. But you still
> won't be able to test it properly. At least not that piece of code where
> it will segfault when user runs it

Huh? A segfault is a result, generally, of one of two things: a runaway
pointer, or an allocation failure - you know, the very thing we're
suggesting you actually design your code to test for.

> (here I assume that user will be able
> to see it, perhaps on windows). A better thing to do is to test malloc()
> failure in one place, and possibly do what you can do there, and abort.

Really? Okay, fine. I've got allocated data buffers *with live data* in
793 different places in the code. The only way your "one place" is going
to be able to "do what you can there" and save the data is if every
single piece of data in the entire program is a freaking *global*, which
is *not* gonna happen.

Now, if I don't use this half-baked notion of "allocate or die", I can
report the failure to the caller, and then to its caller, and so on and
so forth, with each level doing whatever is appropriate for the data it
has in its care, *none* of which your method has *any* ability to do.

But hey, it's not like data matters, right? Who cares, data's worthless,
just crash the app.


>> > Yes, *real*. No, g_malloc() aborting an application is not a real
>> > problem. Not for a regular desktop application.
>>
>> You have just had pointed out to you a time when it has been a problem
>> for a user.
>
> Yeah, mozilla leaking too much. Or evolution leaking too much (?).

Could be either. Point is, we know that _real world_ applications _are_
dying from this design principle, which means that while today it's "only
a browser", there's no telling what it will be tomorrow.

>> I've previously pointed out times when applications have given me a
>> chance to recover the situation and it has avoided me loosing a lot of
>> work.
>
> Avoiding losing your work in an emergency condition is just a different
> story

No, it's the same story. Application tried to allocate something,
couldn't, *died* and took the data with it. Depending on the app - and
the data - this would be grounds for anything from simply pulling hair
out to actually hunting down the developer with a baseball bat. Or a
lawyer.

>> Not necessarily. For example, if you have done your job correctly the
>> *recovery* code already has the memory it needs allocated, so that can
>> run successfully.
>
> Recovery code will be able to run successfully, so what?

"So what" is that my data wasn't hooped by your brain-dead strategy of
simply aborting on error, that's what. I know you don't think users'
data actually *means* anything, but I can assure you, the *user* thinks
it does.

ymun...@gmail.com

unread,
Jan 28, 2008, 8:57:07 PM1/28/08
to
On Jan 28, 6:36 pm, Richard Heathfield <r...@see.sig.invalid> wrote:
> Kelsey Bjarnason said:
>
> > [snips]
>
> > On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
>
> <snip>
>
> >> All this apart from real
> >> problems you have to solve. Yes, *real*. No, g_malloc() aborting an
> >> application is not a real problem. Not for a regular desktop
> >> application.
>
> > Except that at least one person *here*, in a comparatively small
> > community, has reported application crashes *precisely* due to this.
>
> Yes, Kelsey, but so what? Read what he's saying: this is *not* a real
> problem. It's only data - how could mere data possibly be important enough
> to justify spending a little extra time working out how to salvage it in
> the event of an allocation failure?

Strawman.

Randy Howard

unread,
Jan 28, 2008, 11:16:41 PM1/28/08
to
On Mon, 28 Jan 2008 18:36:37 -0600, Richard Heathfield wrote
(in article <zsCdnYj1xZem6QPa...@bt.com>):

> Kelsey Bjarnason said:
>
>> [snips]
>>
>> On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
>>
> <snip>
>
>>> All this apart from real
>>> problems you have to solve. Yes, *real*. No, g_malloc() aborting an
>>> application is not a real problem. Not for a regular desktop
>>> application.
>>
>> Except that at least one person *here*, in a comparatively small
>> community, has reported application crashes *precisely* due to this.
>
> Yes, Kelsey, but so what? Read what he's saying: this is *not* a real
> problem. It's only data - how could mere data possibly be important enough
> to justify spending a little extra time working out how to salvage it in
> the event of an allocation failure?

Apparently, "regular old desktop applications", such as Office suites,
database front-ends, image management programs like Photoshop, Gimp,
etc., Mail applications and such, all contain information too worthless
to be worth wasting the precious developer's time on. What's a few
hours of work here or there on the user's behalf, when the developer
has a LAN party to go to, or needs to practice riding his unicycle up
and down the hall?

I wonder what the reaction would be if their favorite 'all the bells
and whistles' IDE blew up in their face and they lost all the source
code changes they had made in the last few hours? (All four lines of
them)


>> I wish I knew where this notion of "Hey, it's just an application, feel
>> free to kill it because it's 3:00, or the sky is blue, or whatever other
>> random event has occurred" has come from. I've been cranking apps for
>> most of 30 years now, and I have *never* found it acceptable for an
>> application to simply terminate, unless there is absolutely no other
>> possible option.
>
> You're a dinosaur who has failed to adapt to the Postmodernist school of
> programming, where anything goes, any old garbage is acceptable, users are
> worth nothing, and their data is worth rather less than nothing. Forget
> best software engineering practice, because it's old hat nowadays - if you
> want robustness, buy a Volvo.

glibfoo->gCreateMassiveAppWithgoverhead(GIGABYTE);
/* pretend like nothing bad can happen here, they're only dumb
* users. Besides, the code is open source, if they don't like
* it, they can bloody well fix it by themselves
*/

>
> <snip>
>
>

--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Randy Howard

unread,
Jan 28, 2008, 11:33:52 PM1/28/08
to
On Mon, 28 Jan 2008 17:30:50 -0600, ymun...@gmail.com wrote
(in article
<03141a7b-0c59-4d73...@s12g2000prg.googlegroups.com>):

> On Jan 28, 1:39 pm, Flash Gordon <s...@flash-gordon.me.uk> wrote:

>>> No idea, ask the developers of that buggy application.
>>> Failed fopen() is not an exceptional condition. Failed
>>> malloc() is. Or we are using different vocabularies.
>>
>> The point is that they both require similar recovery strategies.
>
> The point is that they don't. If fopen() fails, there is nothing
> to recover from.

False. If fopen() fails, it could have been because the user had a
typo in a filename he wanted to open in another window to cut/paste
from. When you bail out of the app because this file couldn't be
opened, that's just plain /stupid/. There are cases where a fopen()
failure could be critical with no possible way to recover, continue, or
retry, but they are rare.

> Though if all your application does is fopen(),
> then you can safely abort() when fopen() fails.

Or, you could try and determine why it failed, and take corrective
action, either automatically, or at the user's direction. But hey,
that cuts into the Xbox360 time, eh?

>>>> To my mind, there's no difference in effort required to handle a NULL
>>>> return
>>>> from fopen(), than a NULL return from malloc(). Maybe more typing.
>>
>>> Then you are just really good. Because it's enormously more
>>> typing.
>>
>> Not necessarily.
>
> So, you work with a list, and you append an element to it.
> Now you do list = g_list_append(list, something); with malloc
> error handling you'll have to test whether list_append()
> succeeded. Not much more typing, no. A little bit more, huh?
> C++ exceptions would be appropriate here, but manual error
> checking in C code *is* much much more typing.

No, it's way better if the guy happens to have a dozen apps open at the
moment, and this one is really critical work that he's been entering
data into for the last 2 hours. You could do this:

Display a message to the effect of "Unable to add new record due to an
out of memory condition, please close some other applications if you
would like to try again, or save the work in progress to prevent data
loss"

But instead, this /wonderfully/ designed application aborts and dumps
all his work. That's so much better, right? Clearly this "simpler"
solution is much better than actually protecting the user's data in
glib land. I just can't figure out how they convinced anyone to use
it.


Maybe the real issue with open source is who it lets into the party,
not how much the cover charge is.

>>> And more than that, it's more design questions too:
>>> "what do I do in this situation,
>>
>> That is part of the normal design process.
>>
>>> which I can't even possibly
>>> test?"
>>
>> I can test it relatively easily. For example, I can use a malloc wrapper
>> which allows me to force a return of a null pointer when I want during
>> testing. Or I can use the debugger to put a breakpoint in and change the
>> pointer value to null at the point I want to trigger the failure.
>
> There are about five bazillion allocations, debugger won't do. Random
> malloc() failures will do as a nice stress test, yes. But you still
> won't be able to test it properly. At least not that piece of code
> where it will segfault when user runs it (here I assume that user
> will be able to see it, perhaps on windows).

If you check, it won't segfault. That's the whole point. You'll
detect an error, and handle it, instead of merrily trudging along and
counting on the runtime to abort your entire process so you don't have
to worry about branch prediction hits in your wonderfully bloated, yet
somehow pseudo-optimized pile of crap you foist on the user community.

> A better thing to do
> is to test malloc() failure in one place, and possibly do what you
> can do there, and abort.

That is an option, out of many that are available in general. With
glib or other designs with that model, that's pretty much all you're
left with. Any chance of doing anything even remotely professional in
light of an allocation failure is out the window.

>>> All this apart from real problems you have to solve.
>>
>> Yes, this is called software design, a task that people writing software
>> should perform.
>>
>>> Yes, *real*. No, g_malloc() aborting an application is not
>>> a real problem. Not for a regular desktop application.
>>
>> You have just had pointed out to you a time when it has been a problem
>> for a user.
>
> Yeah, mozilla leaking too much. Or evolution leaking too much (?).
> It would be nice to see something more substantial than "I know
> for a fact" (debugged it, looked at the core file?). And would
> be nice to hear about gedit or gnumeric crashing because of malloc()
> failure.

Turn off overcommit, fire up some quick command line tools to chew up
ram and fill up the swap, and watch them all start crashing. Easy.

>> I've previously pointed out times when applications have
>> given me a chance to recover the situation and it has avoided me loosing
>> a lot of work.
>
> Avoiding losing your work in an emergency condition is just
> a different story,

No, it isn't. In the majority of cases where a malloc() fails other
than immediately after program launch there is a potential for data
loss, file corruption, leaving stale files laying around, etc.

> say you can have your application lost its
> terminal or X connection, in those cases you can possibly do
> something to save user's work. And that's something you can
> (try to) do from inside g_malloc() when malloc() fails. It's
> not necessary to write a g_list_append() which can fail for
> that.

What about when the g_list_append() is the thing that fails, and it's
trying to add the 4000th new element to this list, of which the 3999
other elements are already in, but the data has not been saved? This
little "I didn't feel it was necessary to handle that" comment isn't
going to make the user happy at all. But who cares, it's free software
right, they have no complaints coming.

> So, you got an event, you need to put it into the event queue.
> Either you allocate memory for that (and it fails), or you
> preallocate memory, it is not enough, and you try to allocate
> again (and it fails). What can you do apart from some emergency
> action (saving important data or something) and exit? How
> do you "recover"?

That little act of "saving important data or something" isn't a minor
thing. You /might/ not be able to recover completely and continue if
nothing else happened. You should be able to save work in progress
though. You might even be able to notify that the user that you're
having an issue with grabbing more memory, and let the user try and
shut down some other apps to make it available.

But what the hell, that's just too much trouble.

dj3v...@csclub.uwaterloo.ca.invalid

unread,
Jan 28, 2008, 11:39:20 PM1/28/08
to
In article <0001HW.C3C404C9...@news.verizon.net>,

Randy Howard <randy...@FOOverizonBAR.net> wrote:
>On Mon, 28 Jan 2008 18:36:37 -0600, Richard Heathfield wrote
>(in article <zsCdnYj1xZem6QPa...@bt.com>):

>> You're a dinosaur who has failed to adapt to the Postmodernist school of

>> programming, where anything goes, any old garbage is acceptable, users are
>> worth nothing, and their data is worth rather less than nothing. Forget
>> best software engineering practice, because it's old hat nowadays - if you
>> want robustness, buy a Volvo.
>
> glibfoo->gCreateMassiveAppWithgoverhead(GIGABYTE);
> /* pretend like nothing bad can happen here, they're only dumb
> * users. Besides, the code is open source, if they don't like
> * it, they can bloody well fix it by themselves
> */

assert(user_didnt_try_to_frotz_a_widget_that_was_already_frobbed);

That bug report hasn't gone anywhere. How much do you want to bet that
if a commercial program was dumping core because two internal checks
disagreed about what was valid and a user reported the problem, how to
reproduce it, and a suggested fix, it would be fixed within two years
of being reported?


dave
(yes, it's fixed in my local build. no, that's not the point.)

--
Dave Vandervies dj3vande at eskimo dot com

Nit-picking, angels-on-pinhead-counting, pedant-delighting
counter-example:
--Eric Sosman in comp.lang.c

Randy Howard

unread,
Jan 28, 2008, 11:40:52 PM1/28/08
to
On Mon, 28 Jan 2008 19:57:07 -0600, ymun...@gmail.com wrote
(in article
<91e186db-ea74-442b...@i7g2000prf.googlegroups.com>):

It's not a strawman at all. He simply taking your position "aborting

an application is not a real problem. Not for a regular desktop

application" and putting it in real world terms.

Apparently there might exist for you some class of "irregular
applications" that are worthy of actual error handling. But "regular
desktop applications" deserve no such effort.

ymun...@gmail.com

unread,
Jan 29, 2008, 3:12:51 AM1/29/08
to
On Jan 28, 10:33 pm, Randy Howard <randyhow...@FOOverizonBAR.net>
wrote:
> On Mon, 28 Jan 2008 17:30:50 -0600, ymunt...@gmail.com wrote
> (in article
> <03141a7b-0c59-4d73-af65-4f88da892...@s12g2000prg.googlegroups.com>):

>
> > On Jan 28, 1:39 pm, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> >>> No idea, ask the developers of that buggy application.
> >>> Failed fopen() is not an exceptional condition. Failed
> >>> malloc() is. Or we are using different vocabularies.
>
> >> The point is that they both require similar recovery strategies.
>
> > The point is that they don't. If fopen() fails, there is nothing
> > to recover from.
>
> False. If fopen() fails, it could have been because the user had a
> typo in a filename he wanted to open in another window to cut/paste
> from. When you bail out of the app because this file couldn't be
> opened, that's just plain /stupid/. There are cases where a fopen()
> failure could be critical with no possible way to recover, continue, or
> retry, but they are rare.

There is nothing to recover because failure of fopen()
is a normal situation. Absolutely different from a failure
of malloc() when you are trying to allocate a structure
to push into the event queue to scroll text a bit later.

>
> > Though if all your application does is fopen(),
> > then you can safely abort() when fopen() fails.
>
> Or, you could try and determine why it failed, and take corrective
> action, either automatically, or at the user's direction. But hey,
> that cuts into the Xbox360 time, eh?

Strawman you see. We were talking about malloc() and
you tell my application will crash when fopen() fails.

Note that if your application can ask user about something,
then it does more than fopen(). If it can take any
action when fopen() fails, then it does more. That's
what I meant. cat utility doesn't have much to do
if it can't open the file it's supposed to read.
A gui application doesn't have much to do if it
doesn't have memory to draw stuff it draws.

>
> >>>> To my mind, there's no difference in effort required to handle a NULL
> >>>> return
> >>>> from fopen(), than a NULL return from malloc(). Maybe more typing.
>
> >>> Then you are just really good. Because it's enormously more
> >>> typing.
>
> >> Not necessarily.
>
> > So, you work with a list, and you append an element to it.
> > Now you do list = g_list_append(list, something); with malloc
> > error handling you'll have to test whether list_append()
> > succeeded. Not much more typing, no. A little bit more, huh?
> > C++ exceptions would be appropriate here, but manual error
> > checking in C code *is* much much more typing.
>
> No, it's way better if the guy happens to have a dozen apps open at the
> moment, and this one is really critical work that he's been entering
> data into for the last 2 hours. You could do this:
>
> Display a message to the effect of "Unable to add new record due to an
> out of memory condition, please close some other applications if you
> would like to try again, or save the work in progress to prevent data
> loss"

BS. You can't display message if you don't have memory. You could
reserve some, specially for the message, and *try* to display it.
But it won't show up anyway.

> But instead, this /wonderfully/ designed application aborts and dumps
> all his work.

It's not necessary to dump the user's work. On the contrary,
you should try to save his work if you can. But I'll be glad
to see what you would do in a dictionary application. Or in
an mp3 player. If you believe that an mp3 player shouldn't
abort when it can't allocate memory for a playlist, it's a
fine opinion, and you simply shouldn't use mp3 players
based on glib. Others still will (you know why? because
it won't abort)

> That's so much better, right? Clearly this "simpler"
> solution is much better than actually protecting the user's data in
> glib land. I just can't figure out how they convinced anyone to use
> it.
>
> Maybe the real issue with open source is who it lets into the party,
> not how much the cover charge is.

So, strawman.


> >>> And more than that, it's more design questions too:
> >>> "what do I do in this situation,
>
> >> That is part of the normal design process.
>
> >>> which I can't even possibly
> >>> test?"
>
> >> I can test it relatively easily. For example, I can use a malloc wrapper
> >> which allows me to force a return of a null pointer when I want during
> >> testing. Or I can use the debugger to put a breakpoint in and change the
> >> pointer value to null at the point I want to trigger the failure.
>
> > There are about five bazillion allocations, debugger won't do. Random
> > malloc() failures will do as a nice stress test, yes. But you still
> > won't be able to test it properly. At least not that piece of code
> > where it will segfault when user runs it (here I assume that user
> > will be able to see it, perhaps on windows).
>
> If you check, it won't segfault. That's the whole point. You'll
> detect an error, and handle it, instead of merrily trudging along and
> counting on the runtime to abort your entire process so you don't have
> to worry about branch prediction hits in your wonderfully bloated, yet
> somehow pseudo-optimized pile of crap you foist on the user community.

So, we got to crap finally. Good. Think what you do when you
next time run a shell, or python, or a perl script. Aren't you
afraid of using gui applications, by the way? Or can you
present an example of one which continues working after malloc()
fails? Source code please.

>
> > A better thing to do
> > is to test malloc() failure in one place, and possibly do what you
> > can do there, and abort.
>
> That is an option, out of many that are available in general. With
> glib or other designs with that model, that's pretty much all you're
> left with. Any chance of doing anything even remotely professional in
> light of an allocation failure is out the window.

Professional talking here! Have you written some application
for us mere mortals to learn from?

>
> >>> All this apart from real problems you have to solve.
>
> >> Yes, this is called software design, a task that people writing software
> >> should perform.
>
> >>> Yes, *real*. No, g_malloc() aborting an application is not
> >>> a real problem. Not for a regular desktop application.
>
> >> You have just had pointed out to you a time when it has been a problem
> >> for a user.
>
> > Yeah, mozilla leaking too much. Or evolution leaking too much (?).
> > It would be nice to see something more substantial than "I know
> > for a fact" (debugged it, looked at the core file?). And would
> > be nice to hear about gedit or gnumeric crashing because of malloc()
> > failure.
>
> Turn off overcommit, fire up some quick command line tools to chew up
> ram and fill up the swap, and watch them all start crashing. Easy.

Even easier, use kill (1). So?

>
> >> I've previously pointed out times when applications have
> >> given me a chance to recover the situation and it has avoided me loosing
> >> a lot of work.
>
> > Avoiding losing your work in an emergency condition is just
> > a different story,
>
> No, it isn't. In the majority of cases where a malloc() fails other
> than immediately after program launch there is a potential for data
> loss, file corruption, leaving stale files laying around, etc.
>
> > say you can have your application lost its
> > terminal or X connection, in those cases you can possibly do
> > something to save user's work. And that's something you can
> > (try to) do from inside g_malloc() when malloc() fails. It's
> > not necessary to write a g_list_append() which can fail for
> > that.
>
> What about when the g_list_append() is the thing that fails, and it's
> trying to add the 4000th new element to this list, of which the 3999
> other elements are already in, but the data has not been saved? This
> little "I didn't feel it was necessary to handle that" comment isn't
> going to make the user happy at all. But who cares, it's free software
> right, they have no complaints coming.

Huh?

> > So, you got an event, you need to put it into the event queue.
> > Either you allocate memory for that (and it fails), or you
> > preallocate memory, it is not enough, and you try to allocate
> > again (and it fails). What can you do apart from some emergency
> > action (saving important data or something) and exit? How
> > do you "recover"?
>
> That little act of "saving important data or something" isn't a minor
> thing. You /might/ not be able to recover completely and continue if
> nothing else happened. You should be able to save work in progress
> though. You might even be able to notify that the user that you're
> having an issue with grabbing more memory, and let the user try and
> shut down some other apps to make it available.
>
> But what the hell, that's just too much trouble.

Strawman. Who said you shouldn't save data? Do save it. And
exit the application.

ymun...@gmail.com

unread,
Jan 29, 2008, 3:25:48 AM1/29/08
to

Oh yes. Easy. How many lines of code is that? And how
many lines of code will you get if you do it ten times?
That is, lines of untested code (no, I won't buy the
tales that you will test it. You won't)

>
> >> I can test it relatively easily. For example, I can use a malloc
> >> wrapper which allows me to force a return of a null pointer when I want
> >> during testing. Or I can use the debugger to put a breakpoint in and
> >> change the pointer value to null at the point I want to trigger the
> >> failure.
> > There are about five bazillion allocations, debugger won't do. Random
> > malloc() failures will do as a nice stress test, yes. But you still
> > won't be able to test it properly. At least not that piece of code where
> > it will segfault when user runs it
>
> Huh? A segfault is a result, generally, of one of two things: a runaway
> pointer, or an allocation failure - you know, the very thing we're
> suggesting you actually design your code to test for.

I'm saying that you got so many possible segfault places
that you won't test the one where it will actually segfault.

>
> > (here I assume that user will be able
> > to see it, perhaps on windows). A better thing to do is to test malloc()
> > failure in one place, and possibly do what you can do there, and abort.
>
> Really? Okay, fine. I've got allocated data buffers *with live data* in
> 793 different places in the code. The only way your "one place" is going
> to be able to "do what you can there" and save the data is if every
> single piece of data in the entire program is a freaking *global*, which
> is *not* gonna happen.
>
> Now, if I don't use this half-baked notion of "allocate or die", I can
> report the failure to the caller, and then to its caller, and so on and
> so forth, with each level doing whatever is appropriate for the data it
> has in its care, *none* of which your method has *any* ability to do.
>
> But hey, it's not like data matters, right? Who cares, data's worthless,
> just crash the app.

Okay, okay. After we crashed the application and lost user data,
let's talk about that old boring main loop. Who is it going to
report errors to? After we failed to process an event in the user
code, user code returns an error to the events dispatcher. What
does that do? Pretends nothing happened? What do you do if signal
emission failed because you can't allocate memory required for
the emission? The callbacks must be called, otherwise you get
all sorts of funny results, including data loss. You just got
to quit the application, that's all you can do. Save the data
if you can, certainly.

>
> >> > Yes, *real*. No, g_malloc() aborting an application is not a real
> >> > problem. Not for a regular desktop application.
>
> >> You have just had pointed out to you a time when it has been a problem
> >> for a user.
>
> > Yeah, mozilla leaking too much. Or evolution leaking too much (?).
>
> Could be either. Point is, we know that _real world_ applications _are_
> dying from this design principle, which means that while today it's "only
> a browser", there's no telling what it will be tomorrow.

Err, if an application eats too much memory then the die-on-oom
simply doesn't work for it. It's the application bug if it eats
too much memory and dies. When gedit crashes because of malloc()
failure, *then* there will be a gedit bug. Hypothetical abort()
in gedit is not something I would worry about if I were a gedit
developer.

>
> >> I've previously pointed out times when applications have given me a
> >> chance to recover the situation and it has avoided me loosing a lot of
> >> work.
>
> > Avoiding losing your work in an emergency condition is just a different
> > story
>
> No, it's the same story. Application tried to allocate something,
> couldn't, *died* and took the data with it. Depending on the app - and
> the data - this would be grounds for anything from simply pulling hair
> out to actually hunting down the developer with a baseball bat. Or a
> lawyer.

So don't lose data? You can avoid losing data with glib, yes.
Just please stop talking this stuff about losing data. Data
must not be lost, period. An application may abort on malloc()
failure, period. These two *are* possible to combine.

>
> >> Not necessarily. For example, if you have done your job correctly the
> >> *recovery* code already has the memory it needs allocated, so that can
> >> run successfully.
>
> > Recovery code will be able to run successfully, so what?
>
> "So what" is that my data wasn't hooped by your brain-dead strategy of
> simply aborting on error, that's what. I know you don't think users'
> data actually *means* anything, but I can assure you, the *user* thinks
> it does.

Sorry, I didn't say lose data. I said you can't continue working
as nothing happened after that. "Recovery code will be able to run
successfully", right. Now read what you snipped, and *then* argue.

Randy Howard

unread,
Jan 29, 2008, 3:34:45 AM1/29/08
to
On Tue, 29 Jan 2008 02:12:51 -0600, ymun...@gmail.com wrote
(in article
<a39e790e-bd73-44a2...@v67g2000hse.googlegroups.com>):


>>> So, you work with a list, and you append an element to it.
>>> Now you do list = g_list_append(list, something); with malloc
>>> error handling you'll have to test whether list_append()
>>> succeeded. Not much more typing, no. A little bit more, huh?
>>> C++ exceptions would be appropriate here, but manual error
>>> checking in C code *is* much much more typing.
>>
>> No, it's way better if the guy happens to have a dozen apps open at the
>> moment, and this one is really critical work that he's been entering
>> data into for the last 2 hours. You could do this:
>>
>> Display a message to the effect of "Unable to add new record due to an
>> out of memory condition, please close some other applications if you
>> would like to try again, or save the work in progress to prevent data
>> loss"
>
> BS. You can't display message if you don't have memory. You could
> reserve some, specially for the message, and *try* to display it.
> But it won't show up anyway.

Sigh. A malloc() failure does not necessarily mean that you are out
of memory in the entire system, or even in your own process. It means
that a specific call to malloc() failed. It's strange that you say
this is "BS", when I have seen these sorts of messages appear on
terminals and displays periodically in various applications over the
last 30 years. Maybe they used magic fairy dust.

>> But instead, this /wonderfully/ designed application aborts and dumps
>> all his work.
>
> It's not necessary to dump the user's work. On the contrary,
> you should try to save his work if you can. But I'll be glad
> to see what you would do in a dictionary application.

Are you claiming that no dictionary application offers any recovery for
a malloc() failure than an abort? If not, what are you trying to say?

> If you believe that an mp3 player shouldn't
> abort when it can't allocate memory for a playlist, it's a
> fine opinion, and you simply shouldn't use mp3 players
> based on glib.

On that we can agree.

> Others still will (you know why? because it won't abort)

I can't parse this with any degree of confidence.

At any rate, it seems fairly clear that neither of us is going to move
the other, so it seems pointless to continue.

Nick Keighley

unread,
Jan 29, 2008, 3:56:12 AM1/29/08
to
On 29 Jan, 08:25, ymunt...@gmail.com wrote:
> On Jan 28, 11:40 am, Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
> > On Mon, 28 Jan 2008 15:30:50 -0800, ymuntyan wrote:

> > >> > No idea, ask the developers of that buggy application. Failed fopen()
> > >> > is not an exceptional condition. Failed malloc() is. Or we are using
> > >> > different vocabularies.
>
> > >> The point is that they both require similar recovery strategies.
>
> > > The point is that they don't. If fopen() fails, there is nothing to
> > > recover from.
>
> > If my fopen fails and I can't load my app's config file, I can't get the
> > preferred options.  Depending on the app, this could be anything from a
> > minor annoyance to a critical failure.  In every one of those cases,
> > there is something to recover from.
>
> > If my fopen fails because the user has no read permissions (or no write
> > permissions, if he's trying to open for write), there is something to
> > recover from - let him know he has no permissions, go back to the file
> > select dialog (or whatever called fopen) and let the user decide what to
> > do about it - choose a different file name, fix the permissions, whatever.
>
> > I'm sorry, but "there's nothing to recover from" is just so completely
> > out of touch with reality I can't believe you said it.
>
> > > So, you work with a list, and you append an element to it. Now you do
> > > list = g_list_append(list, something); with malloc error handling you'll
> > > have to test whether list_append() succeeded.

does g_list_append() allocate memory?

very few

> And how
> many lines of code will you get if you do it ten times?

still very few

> That is, lines of untested code (no, I won't buy the
> tales that you will test it. You won't)

it seems you're assumptions about his development methodology


> > >> I can test it relatively easily. For example, I can use a malloc
> > >> wrapper which allows me to force a return of a null pointer when I want
> > >> during testing. Or I can use the debugger to put a breakpoint in and
> > >> change the pointer value to null at the point I want to trigger the
> > >> failure.
>
> > > There are about five bazillion allocations, debugger won't do.

and the wrapper?

> > > Random
> > > malloc() failures will do as a nice stress test, yes. But you still
> > > won't be able to test it properly. At least not that piece of code where
> > > it will segfault when user runs it
>
> > Huh?  A segfault is a result, generally, of one of two things: a runaway
> > pointer, or an allocation failure - you know, the very thing we're
> > suggesting you actually design your code to test for.
>
> I'm saying that you got so many possible segfault places
> that you won't test the one where it will actually segfault.

there won't be *any* segfault places. You ALWAYS test the return from
malloc().


> > > (here I assume that user will be able
> > > to see it, perhaps on windows). A better thing to do is to test malloc()
> > > failure in one place, and possibly do what you can do there, and abort.
>
> > Really?  Okay, fine.  I've got allocated data buffers *with live data* in
> > 793 different places in the code.  The only way your "one place" is going
> > to be able to "do what you can there" and save the data is if every
> > single piece of data in the entire program is a freaking *global*, which
> > is *not* gonna happen.
>
> > Now, if I don't use this half-baked notion of "allocate or die", I can
> > report the failure to the caller, and then to its caller, and so on and
> > so forth, with each level doing whatever is appropriate for the data it
> > has in its care, *none* of which your method has *any* ability to do.
>
> > But hey, it's not like data matters, right?  Who cares, data's worthless,
> > just crash the app.
>
> Okay, okay. After we crashed the application and lost user data,

no no no! The point is you do something with the user data
*before* you terminate the application.

> let's talk about that old boring main loop. Who is it going to
> report errors to?

I'm not sure what your loop does.


> After we failed to process an event in the user
> code, user code returns an error to the events dispatcher. What
> does that do?

if the user code saves the data the event loop can terminate.
Your crashing malloc() doesn't allow this option.
You make the decisions in the user code which understands the
application and not in the malloc library.


> Pretends nothing happened? What do you do if signal
> emission failed because you can't allocate memory required for
> the emission? The callbacks must be called, otherwise you get
> all sorts of funny results, including data loss. You just got
> to quit the application, that's all you can do. Save the data
> if you can, certainly.

but you can't do that in your code!


> > >> > Yes, *real*. No, g_malloc() aborting an application is not a real
> > >> > problem. Not for a regular desktop application.
>
> > >> You have just had pointed out to you a time when it has been a problem
> > >> for a user.
>
> > > Yeah, mozilla leaking too much. Or evolution leaking too much (?).
>
> > Could be either.  Point is, we know that _real world_ applications _are_
> > dying from this design principle, which means that while today it's "only
> > a browser", there's no telling what it will be tomorrow.
>
> Err, if an application eats too much memory then the die-on-oom
> simply doesn't work for it. It's the application bug if it eats
> too much memory and dies. When gedit crashes because of malloc()
> failure, *then* there will be a gedit bug. Hypothetical abort()
> in gedit is not something I would worry about if I were a gedit
> developer.

why not?


> > >> I've previously pointed out times when applications have given me a
> > >> chance to recover the situation and it has avoided me loosing a lot of
> > >> work.
>
> > > Avoiding losing your work in an emergency condition is just a different
> > > story
>
> > No, it's the same story.  Application tried to allocate something,
> > couldn't, *died* and took the data with it.  Depending on the app - and
> > the data - this would be grounds for anything from simply pulling hair
> > out to actually hunting down the developer with a baseball bat.  Or a
> > lawyer.
>
> So don't lose data? You can avoid losing data with glib, yes.
> Just please stop talking this stuff about losing data. Data
> must not be lost, period. An application may abort on malloc()
> failure, period. These two *are* possible to combine.

how? This makes no sense.


> > >> Not necessarily. For example, if you have done your job correctly the
> > >> *recovery* code already has the memory it needs allocated, so that can
> > >> run successfully.
>
> > > Recovery code will be able to run successfully, so what?
>
> > "So what" is that my data wasn't hooped by your brain-dead strategy of
> > simply aborting on error, that's what.  I know you don't think users'
> > data actually *means* anything, but I can assure you, the *user* thinks
> > it does.
>
> Sorry, I didn't say lose data. I said you can't continue working
> as nothing happened after that. "Recovery code will be able to run
> successfully", right. Now read what you snipped, and *then* argue

"recovery" includes saving data and terminating.


--
Nick Keighley

Flash Gordon

unread,
Jan 29, 2008, 3:54:28 AM1/29/08
to
ymun...@gmail.com wrote, On 28/01/08 23:30:

As others have pointed out, that is a good way to stop people using your
apps.

>>>> To my mind, there's no difference in effort required to handle a NULL
>>>> return
>>>> from fopen(), than a NULL return from malloc(). Maybe more typing.
>>> Then you are just really good. Because it's enormously more
>>> typing.
>> Not necessarily.
>
> So, you work with a list, and you append an element to it.
> Now you do list = g_list_append(list, something); with malloc
> error handling you'll have to test whether list_append()
> succeeded. Not much more typing, no. A little bit more, huh?
> C++ exceptions would be appropriate here, but manual error
> checking in C code *is* much much more typing.

Not always. I've done it using structured programming in assembler
without implementing exceptions and at each point I checked the status
and propagated the error until it could be handled. The handling
consisted of processing what it had memory for giving degraded
performance instead of giving up which would not have been acceptable.
It was also easy to do because I new resources were limited and designed
the SW assuming that they could run out.

>>> And more than that, it's more design questions too:
>>> "what do I do in this situation,
>> That is part of the normal design process.
>>
>>> which I can't even possibly
>>> test?"
>> I can test it relatively easily. For example, I can use a malloc wrapper
>> which allows me to force a return of a null pointer when I want during
>> testing. Or I can use the debugger to put a breakpoint in and change the
>> pointer value to null at the point I want to trigger the failure.
>
> There are about five bazillion allocations, debugger won't do. Random
> malloc() failures will do as a nice stress test, yes. But you still
> won't be able to test it properly. At least not that piece of code
> where it will segfault when user runs it (here I assume that user
> will be able to see it, perhaps on windows). A better thing to do
> is to test malloc() failure in one place, and possibly do what you
> can do there, and abort.

You propagate the error upwards until it can be handled sensibly. So
most of your malloc failure tests are simply returning a failure code
after maybe some simple local recovery. Far better not to loose the
users hard work for a little thought in design and implementation.

>>> All this apart from real problems you have to solve.
>> Yes, this is called software design, a task that people writing software
>> should perform.
>>
>>> Yes, *real*. No, g_malloc() aborting an application is not
>>> a real problem. Not for a regular desktop application.
>> You have just had pointed out to you a time when it has been a problem
>> for a user.
>
> Yeah, mozilla leaking too much. Or evolution leaking too much (?).
> It would be nice to see something more substantial than "I know
> for a fact" (debugged it, looked at the core file?). And would
> be nice to hear about gedit or gnumeric crashing because of malloc()
> failure.

Well, I have seen the Lotus Notes client report out-of-memory on
attempting to open a window. The Notes client did not crash, it reported
it and left the dialogue box there. When I could I closed down some
other applications (not immediately) and avoided loosing partly typed
emails. I've also had VMWare report out-of-resource at times when the
only resource that was tight was memory, and again it gave me the chance
to recover the situation which saved me significant work because I had
two VMs running and the state between them was important and took time
setting up.

>> I've previously pointed out times when applications have
>> given me a chance to recover the situation and it has avoided me loosing
>> a lot of work.
>
> Avoiding losing your work in an emergency condition is just
> a different story, say you can have your application lost its
> terminal or X connection, in those cases you can possibly do
> something to save user's work. And that's something you can
> (try to) do from inside g_malloc() when malloc() fails. It's
> not necessary to write a g_list_append() which can fail for
> that.

See above. I *use* applications that do not abort but instead allow me
to keep all my data and continue.

If the X-server itself is passing the event to the application then it
is whether the X-server has the memory that is important. The
application can generate events too, but the application do things to
recover itself.

>> It
>> is an easy problem to handle by allocating the space in advance so that
>> when you get the event you *already* have the space to store it.
>
> So, you got an event, you need to put it into the event queue.
> Either you allocate memory for that (and it fails), or you
> preallocate memory, it is not enough, and you try to allocate
> again (and it fails). What can you do apart from some emergency
> action (saving important data or something) and exit? How
> do you "recover"?

You increase the space allocated *before* you are out so that if it
fails you still have the resources to pop up a dialogue telling the user
and giving them a chance to do something about it.

>>> You may not just lose events
>>> like that. *Everything* must be done in order, or the application is
>>> doomed, and the best it can do is to try to exit as nicely as it can
>>> (like save data or whatever). It can't just pretend nothing happened.
>> William has suggested *not* pretending nothing happened.
>
> Right, he didn't suggest anything.

He did not suggest the specifics because the specifics vary depending on
the situation. However he did say that you don't throw away the users data.

The recovery may be as simple as telling the user there is no memory to
open a new window and let the user continue with the existing ones (I've
*seen* this behaviour). Or it may give the user the option of retrying
or aborting. Or...

>>> No memory => application isn't working.
>> Only if you don't design a suitable recovery process.
>
> Again, no recovery process will be able to make your main loop
> spin happily again. The recovery process can't get memory from
> nowhere (unless by recovery you mean killing parts of application,
> in which case it again doesn't make sense to proceed in normal way).

Well, I've seen GUI applications do sensible things thus avoiding me
from loosing the data. See above.

>>> So you just don't try to handle (that is do something and not exit
>>> the application) possible malloc() failure when you are concatenating
>>> two strings to make up a string to display. Absurd, fine, I'll be
>>> delighted to see an application which handles malloc() failure
>>> when it draws a menu label (it *is* possible, it just doesn't
>>> make sense).
>> I've had windows programs pop up message boxes telling me that they did
>> not have enough memory to open the window I asked them to open. It is
>> possibly, it just requires designing the software to handle the problem.
>
> Perhaps. Except it's not "just". Again, I'll be delighted to see an
> application which handles malloc() failure when it draws a menu label.

I've seen it done on attempting to open a window. Either it was not
enough memory to open the window or it was some component of the window,
either case is not hard to handle.

> Preferably its code, to learn from. Oh, and see the code which works
> with list allocated on heap, which handles every possible failure of
> list_append() (no exceptions and alike please, don't we agree that
> all we need is 'if (failed()) recover()'?).

The precise strategy varies. Fortunately the applications I have to use
*do* handle the problem in ways that avoid me loosing data.
--
Flash Gordon

ymun...@gmail.com

unread,
Jan 29, 2008, 4:23:21 AM1/29/08
to
On Jan 29, 2:56 am, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:

> On 29 Jan, 08:25, ymunt...@gmail.com wrote:
>
>
>
> > On Jan 28, 11:40 am, Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
> > > On Mon, 28 Jan 2008 15:30:50 -0800, ymuntyan wrote:
> > > >> > No idea, ask the developers of that buggy application. Failed fopen()
> > > >> > is not an exceptional condition. Failed malloc() is. Or we are using
> > > >> > different vocabularies.
>
> > > >> The point is that they both require similar recovery strategies.
>
> > > > The point is that they don't. If fopen() fails, there is nothing to
> > > > recover from.
>
> > > If my fopen fails and I can't load my app's config file, I can't get the
> > > preferred options. Depending on the app, this could be anything from a
> > > minor annoyance to a critical failure. In every one of those cases,
> > > there is something to recover from.
>
> > > If my fopen fails because the user has no read permissions (or no write
> > > permissions, if he's trying to open for write), there is something to
> > > recover from - let him know he has no permissions, go back to the file
> > > select dialog (or whatever called fopen) and let the user decide what to
> > > do about it - choose a different file name, fix the permissions, whatever.
>
> > > I'm sorry, but "there's nothing to recover from" is just so completely
> > > out of touch with reality I can't believe you said it.
>
> > > > So, you work with a list, and you append an element to it. Now you do
> > > > list = g_list_append(list, something); with malloc error handling you'll
> > > > have to test whether list_append() succeeded.
>
> does g_list_append() allocate memory?

Yes. It got to put the data somewhere.

You mean nice versus one is very few? OK.

>
> > And how
> > many lines of code will you get if you do it ten times?
>
> still very few

OK.

> > That is, lines of untested code (no, I won't buy the
> > tales that you will test it. You won't)
>
> it seems you're assumptions about his development methodology
>
> > > >> I can test it relatively easily. For example, I can use a malloc
> > > >> wrapper which allows me to force a return of a null pointer when I want
> > > >> during testing. Or I can use the debugger to put a breakpoint in and
> > > >> change the pointer value to null at the point I want to trigger the
> > > >> failure.
>
> > > > There are about five bazillion allocations, debugger won't do.
>
> and the wrapper?

And a code parser which will find all malloc() calls,
and then a script generator which will generate all
possible code paths to make debugger test those
places. I'd be glad to have such a tool, certainly.

>
> > > > Random
> > > > malloc() failures will do as a nice stress test, yes. But you still
> > > > won't be able to test it properly. At least not that piece of code where
> > > > it will segfault when user runs it
>
> > > Huh? A segfault is a result, generally, of one of two things: a runaway
> > > pointer, or an allocation failure - you know, the very thing we're
> > > suggesting you actually design your code to test for.
>
> > I'm saying that you got so many possible segfault places
> > that you won't test the one where it will actually segfault.
>
> there won't be *any* segfault places. You ALWAYS test the return from
> malloc().

Except where you got a bug. In the place you won't
test.

>
> > > > (here I assume that user will be able
> > > > to see it, perhaps on windows). A better thing to do is to test malloc()
> > > > failure in one place, and possibly do what you can do there, and abort.
>
> > > Really? Okay, fine. I've got allocated data buffers *with live data* in
> > > 793 different places in the code. The only way your "one place" is going
> > > to be able to "do what you can there" and save the data is if every
> > > single piece of data in the entire program is a freaking *global*, which
> > > is *not* gonna happen.
>
> > > Now, if I don't use this half-baked notion of "allocate or die", I can
> > > report the failure to the caller, and then to its caller, and so on and
> > > so forth, with each level doing whatever is appropriate for the data it
> > > has in its care, *none* of which your method has *any* ability to do.
>
> > > But hey, it's not like data matters, right? Who cares, data's worthless,
> > > just crash the app.
>
> > Okay, okay. After we crashed the application and lost user data,
>
> no no no! The point is you do something with the user data
> *before* you terminate the application.

So do it. You *can*. Glib doesn't do anything but abort()
by default, naturally, since it can't do anything else.
If you are fine with this, do nothing. If not, write code
which will save the user data.

And man, I didn't say we should lose the user data!

> > > >> Not necessarily. For example, if you have done your job correctly the
> > > >> *recovery* code already has the memory it needs allocated, so that can
> > > >> run successfully.
>
> > > > Recovery code will be able to run successfully, so what?
>
> > > "So what" is that my data wasn't hooped by your brain-dead strategy of
> > > simply aborting on error, that's what. I know you don't think users'
> > > data actually *means* anything, but I can assure you, the *user* thinks
> > > it does.
>
> > Sorry, I didn't say lose data. I said you can't continue working
> > as nothing happened after that. "Recovery code will be able to run
> > successfully", right. Now read what you snipped, and *then* argue
>
> "recovery" includes saving data and terminating.

So do it? Who said you shouldn't it? You can save data
and terminate. But you ought to terminate, with saving
or not, if you use glib. That's it. But I am told that
an application can do more. No it can't. If the main loop
can't push an event onto the event queue, then you're
screwed. No "application performs worse" or "some parts
are not working". (Note, it is not about all applications,
don't talk about failsafe mp3 players or about webservers,
those simply shouldn't use glib)

Yevgen

ymun...@gmail.com

unread,
Jan 29, 2008, 4:36:51 AM1/29/08
to
On Jan 29, 2:54 am, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> ymunt...@gmail.com wrote, On 28/01/08 23:30:

>
> > On Jan 28, 1:39 pm, Flash Gordon <s...@flash-gordon.me.uk> wrote:
> >> Yevgen Muntyan wrote, On 28/01/08 04:17:

[snip]

> >>> You may not just lose events
> >>> like that. *Everything* must be done in order, or the application is
> >>> doomed, and the best it can do is to try to exit as nicely as it can
> >>> (like save data or whatever). It can't just pretend nothing happened.
> >> William has suggested *not* pretending nothing happened.
>
> > Right, he didn't suggest anything.
>
> He did not suggest the specifics because the specifics vary depending on
> the situation. However he did say that you don't throw away the users data.

And I did say you should throw away the users data,
huh? Sheesh, a "little thought", "losing users work".
Bullshit. Or, politely, strawman. Failing to open a
window and continuing work is one thing, it may be
a very nice feature which is impossible with glib.
But it's different from not losing user data. You
can avoid losing user data with glib.

For the record (once more): you should not lose user's
data. Anything changed? Do I contradict with myself?
Care to quote?

Yevgen

Malcolm McLean

unread,
Jan 29, 2008, 4:55:42 AM1/29/08
to

"Kelsey Bjarnason" <kbjar...@gmail.com> wrote in message

>
> Sorry, what, exactly, did I need to check here with malloc error
> handling? What's that you say, nothing at all, since there _is_ no
> malloc involved in adding a node to the list? Ah, yes. Of course, we
> need to allocate the node itself:
>
> NODE *node;
> LIST *list;
>
> ...
>
> node = malloc( sizeof( *node ) );
> if ( node == NULL )
> {
> blah
> }
> else
> {
> list_append( list, node );
> blah
> }
>
> Golly, how unbearably painful.
>
It's unbearbly painful for you, because you wrote "blah" instead of the
error-handling code.
In an sense you are right. A top-notch appplication will check malloc() on
every call, and apply appropriate, custom error-handling. If it fails to
allocate memory for an event the queue will be purged, the application put
into a "default" state, and the user informed. It's just that we don't
believe that your code is genuinely of that quality.
It's much more likely that it is a mess, with every malloc() checked -
you've got the intelligence and consistency to remember that little rule,
but the so-called recovery code often not really recovering the error,
sometimes aborting, sometimes even putting the application into an invalid
state. And it's hard to tease out because there is so much of this
error-handling logic. What's even worse is that it is hard to find bugs in
normal program flow control, because it is obscrured by all the malloc()
error-condition code.

>
> "So what" is that my data wasn't hooped by your brain-dead strategy of
> simply aborting on error, that's what. I know you don't think users'
> data actually *means* anything, but I can assure you, the *user* thinks
> it does.
>
There's one thing worse than lost data. That's corrupted data. Are you sure
that your program won't corrupt user data? Do you test the save strategy, at
every possible point of malloc() failure? How much times does that add to
your development costs? Are development costs important to you? That's a
real question. If you're writing software for spacecraft the answer will be
"no".

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

santosh

unread,
Jan 29, 2008, 4:58:01 AM1/29/08
to
ymun...@gmail.com wrote:

This is why a complex application needs more than one type of
out-of-memory handler. If a fairly large allocation fails, there is a
real chance that a much smaller allocation /can/ succeed, either for
continuing the program's usual work at a slower pace or to pop up a
message box for the user giving him the option of quitting or killing
some other program and retrying.

OTOH, if a small allocation, say a kilobyte or less, fails then we
probably have a serious resource crunch. There is /no/ point in
reducing the allocation size and trying again, nor is there much point
in trying to bring a dialogue box (though you can try). Probably a
sensible strategy is to attempt saving open files (which may or may not
succeed, but it won't hurt to try), attempt to log a message to stderr
or whatever and then exit with a error status.

But even in this severe case an abort() or a segfault or exiting
silently in a library routine is not a good strategy, IMHO.

<snip>

>> No, it's way better if the guy happens to have a dozen apps open at
>> the moment, and this one is really critical work that he's been
>> entering data into for the last 2 hours. You could do this:
>>
>> Display a message to the effect of "Unable to add new record due to
>> an out of memory condition, please close some other applications if
>> you would like to try again, or save the work in progress to prevent
>> data loss"
>
> BS. You can't display message if you don't have memory. You could
> reserve some, specially for the message, and *try* to display it.
> But it won't show up anyway.

Yes. This is why not all allocations in a program can meaningfully have
the same error handling logic. Some allocations may be totally
redundant. Say the program wants to draw a nice splash screen. If
allocation fails here, nothing needs to be done, the program still
attempt running. A splash screen is just eye-candy.

Similarly the program may try to allocate a large buffer for efficiency
and if this fails, it can try running with a much smaller buffer. Again
the error handling is different.

OTOH a failure of a few kilobytes is pretty big blow and the only
sensible thing is to try and log a message, try to close your files and
resources and exit.

Yes, this is work, but the other option is to respond uniformly and
unintelligently to each and every resource acquisition failure, always
terminating abruptly on the user. I have used many such applications
and they are a /big/ annoyance.

>> But instead, this /wonderfully/ designed application aborts and dumps
>> all his work.
>
> It's not necessary to dump the user's work. On the contrary,
> you should try to save his work if you can. But I'll be glad
> to see what you would do in a dictionary application. Or in
> an mp3 player. If you believe that an mp3 player shouldn't
> abort when it can't allocate memory for a playlist, it's a
> fine opinion, and you simply shouldn't use mp3 players
> based on glib. Others still will (you know why? because
> it won't abort)

No. An MP3 player can still run. Perhaps the stupid user tried to put
10000 titles into the playlist. Perhaps memory for this is unavailable
but enough memory is still available to continue running the current
track. As I said error handling depends (or should depend) intimately
on the exact contextual state of the application and it's environment.

A uniform strategy is hardly better than no error handling at all.

<snip>

>> If you check, it won't segfault. That's the whole point. You'll
>> detect an error, and handle it, instead of merrily trudging along and
>> counting on the runtime to abort your entire process so you don't
>> have to worry about branch prediction hits in your wonderfully
>> bloated, yet somehow pseudo-optimized pile of crap you foist on the
>> user community.
>
> So, we got to crap finally. Good. Think what you do when you
> next time run a shell, or python, or a perl script. Aren't you
> afraid of using gui applications, by the way? Or can you
> present an example of one which continues working after malloc()
> fails? Source code please.

In the past I have used a 3D modelling application that would try to
continue the simulation under low memory conditions by turning off
other parts of the program and non-essential parts of the simulation
itself. For example it would switch off background and colour-filling
for the object.

Off course this is a case of a large allocation failure and not a
failure for a few hundred bytes, which would have been essentially
unrecoverable.

<snip>

Malcolm McLean

unread,
Jan 29, 2008, 5:06:14 AM1/29/08
to

"Flash Gordon" <sp...@flash-gordon.me.uk> wrote in message

> Not always. I've done it using structured programming in assembler without
> implementing exceptions and at each point I checked the status and
> propagated the error until it could be handled. The handling consisted of
> processing what it had memory for giving degraded performance instead of
> giving up which would not have been acceptable. It was also easy to do
> because I new resources were limited and designed the SW assuming that
> they could run out.
>
I've done this as well. It was adding so much complexity to code, all
because of allocation failures that couldn't happen. Finally, within BabyX
(my X windows toolkit) there was no way I could think of of propagating the
error conditions back to the caller. Flow control is just too complex with
the whole thign beign held together by a newtwork of function pointers. So I
decided BabyX would use xmalloc().
Then I realised that this released something for string handling. because we
know that those string functions can never return null, code using them is
so much more expressive and flexible.

santosh

unread,
Jan 29, 2008, 5:59:52 AM1/29/08
to
ymun...@gmail.com wrote:

<snip>

> For the record (once more): you should not lose user's
> data. Anything changed? Do I contradict with myself?
> Care to quote?

Yes, but this is made needlessly difficult by GLib which decided to take
high-level action itself, instead of reporting it to it's caller.

In error recovery situations things are difficult enough as it is that
you don't want your library routine to try and make things even more
complicated.

Malcolm McLean

unread,
Jan 29, 2008, 6:32:33 AM1/29/08
to

"santosh" <santo...@gmail.com> wrote in message

> OTOH a failure of a few kilobytes is pretty big blow and the only
> sensible thing is to try and log a message, try to close your files and
> resources and exit.
>
Or nag the user to close down his other applications and give you more
memory. Which is what the X windows handler to xmalloc() does.
Unfortunately, although the nag window itself is designed to be very
resource light, X itself isn't very robust to allocation failures, and I
can't think of any way round that.
There is also no way of demanding extra resources using just the standard
library, other than calling a function on stdin, which is unlikely to be
acceptable.

ymun...@gmail.com

unread,
Jan 29, 2008, 9:33:02 AM1/29/08
to
On Jan 29, 3:58 am, santosh <santosh....@gmail.com> wrote:

Err, for allocations which can "normally" fail, for those big
allocations, you don't use g_malloc and use g_try_malloc instead.
Which can return NULL. What you don't handle in a normal way (that
is you don't check return value because it won't be NULL, let's not
start again about losing user data) is failure on allocation of
a small chunk of memory, like when you are making a string, or
appending a node to a list, or creating a widget.

>
> <snip>
>
> >> No, it's way better if the guy happens to have a dozen apps open at
> >> the moment, and this one is really critical work that he's been
> >> entering data into for the last 2 hours. You could do this:
>
> >> Display a message to the effect of "Unable to add new record due to
> >> an out of memory condition, please close some other applications if
> >> you would like to try again, or save the work in progress to prevent
> >> data loss"
>
> > BS. You can't display message if you don't have memory. You could
> > reserve some, specially for the message, and *try* to display it.
> > But it won't show up anyway.
>
> Yes. This is why not all allocations in a program can meaningfully have
> the same error handling logic. Some allocations may be totally
> redundant. Say the program wants to draw a nice splash screen. If
> allocation fails here, nothing needs to be done, the program still
> attempt running. A splash screen is just eye-candy.
>
> Similarly the program may try to allocate a large buffer for efficiency
> and if this fails, it can try running with a much smaller buffer. Again
> the error handling is different.

So you can do that. g_try_malloc() the buffer if you know that you
will be able to cope with NULL. Same thing with a splash screen:
the core structure, allocation of which will abort (by default,
you can still save your user's data, blah blah blah) your application,
is pretty small. The image you will load into it will be allocated
using g_try_malloc, which can safely fail (at least gtk will do that,
you of course can blindly call g_malloc(MANY_MEGS)).

> OTOH a failure of a few kilobytes is pretty big blow and the only
> sensible thing is to try and log a message, try to close your files and
> resources and exit.
>
> Yes, this is work, but the other option is to respond uniformly and
> unintelligently to each and every resource acquisition failure, always
> terminating abruptly on the user. I have used many such applications
> and they are a /big/ annoyance.
>
> >> But instead, this /wonderfully/ designed application aborts and dumps
> >> all his work.
>
> > It's not necessary to dump the user's work. On the contrary,
> > you should try to save his work if you can. But I'll be glad
> > to see what you would do in a dictionary application. Or in
> > an mp3 player. If you believe that an mp3 player shouldn't
> > abort when it can't allocate memory for a playlist, it's a
> > fine opinion, and you simply shouldn't use mp3 players
> > based on glib. Others still will (you know why? because
> > it won't abort)
>
> No. An MP3 player can still run. Perhaps the stupid user tried to put
> 10000 titles into the playlist. Perhaps memory for this is unavailable
> but enough memory is still available to continue running the current
> track. As I said error handling depends (or should depend) intimately
> on the exact contextual state of the application and it's environment.

Well, if mp3 player author thinks so, he can use data structures
other than glib's ones. Like use his own list instead of GList.
Normally he won't do that, he will use glib's list, and his
application will abort when you try to load a bajillion-title
playlist (10000 is not enough, if your computer won't get memory
for 10000 items, then you won't run that mp3 player in the first
place, we are talking about memory-greedy hippos here).
Perhaps it's too bad, you won't use such a player. For me
it's okay (I can change my mind when I see that player crash,
perhaps).

> A uniform strategy is hardly better than no error handling at all.

First of all, it's not true. Second, huh?

Yevgen

Nick Keighley

unread,
Jan 29, 2008, 10:19:01 AM1/29/08
to
On 29 Jan, 09:23, ymunt...@gmail.com wrote:
> On Jan 29, 2:56 am, Nick Keighley <nick_keighley_nos...@hotmail.com>
> wrote:
> > On 29 Jan, 08:25, ymunt...@gmail.com wrote:
> > > On Jan 28, 11:40 am, Kelsey Bjarnason <kbjarna...@gmail.com> wrote:
> > > > On Mon, 28 Jan 2008 15:30:50 -0800, ymuntyan wrote:

<snip>

> > > > > So, you work with a list, and you append an element to it. Now you do
> > > > > list = g_list_append(list, something); with malloc error handling you'll
> > > > > have to test whether list_append() succeeded.
>
> > does g_list_append() allocate memory?
>
> Yes. It got to put the data somewhere.

in a preallocated piece of memory maybe?

if ((x = malloc(27)) == 0)
{
save_stuff();
exit(FAILURE);
}

list_append(x);

nine? and some of those are brackets

<snip>

sorry, you must have missed "You ALWAYS test the return from malloc()"


> > > > > (here I assume that user will be able
> > > > > to see it, perhaps on windows). A better thing to do is to test malloc()
> > > > > failure in one place, and possibly do what you can do there, and abort.
>
> > > > Really?  Okay, fine.  I've got allocated data buffers *with live data* in
> > > > 793 different places in the code.  The only way your "one place" is going
> > > > to be able to "do what you can there" and save the data is if every
> > > > single piece of data in the entire program is a freaking *global*, which
> > > > is *not* gonna happen.
>
> > > > Now, if I don't use this half-baked notion of "allocate or die", I can
> > > > report the failure to the caller, and then to its caller, and so on and
> > > > so forth, with each level doing whatever is appropriate for the data it
> > > > has in its care, *none* of which your method has *any* ability to do.
>
> > > > But hey, it's not like data matters, right?  Who cares, data's worthless,
> > > > just crash the app.
>
> > > Okay, okay. After we crashed the application and lost user data,
>
> > no no no! The point is you do something with the user data
> > *before* you terminate the application.
>
> So do it. You *can*. Glib doesn't do anything but abort()
> by default, naturally, since it can't do anything else.
> If you are fine with this, do nothing. If not, write code
> which will save the user data.

no this baffles me. If aborting in the malloc() wrapper
isn't the correct option you don't use it...

so...

no I'm still baffled. Why not follow a policy of try and allocate
memory, if it fails take some application specific recovery action?
Only the application can know what to do.


> And man, I didn't say we should lose the user data!

but you have no choice if malloc crashes!


> > > > >> Not necessarily. For example, if you have done your job correctly the
> > > > >> *recovery* code already has the memory it needs allocated, so that can
> > > > >> run successfully.
>
> > > > > Recovery code will be able to run successfully, so what?
>
> > > > "So what" is that my data wasn't hooped by your brain-dead strategy of
> > > > simply aborting on error, that's what.  I know you don't think users'
> > > > data actually *means* anything, but I can assure you, the *user* thinks
> > > > it does.
>
> > > Sorry, I didn't say lose data. I said you can't continue working
> > > as nothing happened after that. "Recovery code will be able to run
> > > successfully", right. Now read what you snipped, and *then* argue
>
> > "recovery" includes saving data and terminating.
>
> So do it? Who said you shouldn't it? You can save data
> and terminate. But you ought to terminate, with saving
> or not, if you use glib.

what? glib only crashes sometimes?

you don't *have* to terminate. You could free some memory.
Or abort some operation. On large long running systems
you don't die just because the user can't display the current
alarm list

> That's it. But I am told that
> an application can do more. No it can't.

sometimes it can.


> If the main loop
> can't push an event onto the event queue, then you're
> screwed.

yes, that's a bit extreme. But if it's comoing from an external
source you could discard it and wait for the repeat.

> No "application performs worse" or "some parts
> are not working".

I think you are mistaken.


> (Note, it is not about all applications,
> don't talk about failsafe mp3 players or about webservers,
> those simply shouldn't use glib)

so what class of application should? Games? Mobile radio Systems?
Database servers?

--
Nick Keighley

ymun...@gmail.com

unread,
Jan 29, 2008, 10:27:00 AM1/29/08
to
On Jan 29, 9:19 am, Nick Keighley <nick_keighley_nos...@hotmail.com>

You missed the meaning of "test".

I don't know why not. You can do that.

>
> > And man, I didn't say we should lose the user data!
>
> but you have no choice if malloc crashes!

malloc doesn't crash.

> > > > > >> Not necessarily. For example, if you have done your job correctly the
> > > > > >> *recovery* code already has the memory it needs allocated, so that can
> > > > > >> run successfully.
>
> > > > > > Recovery code will be able to run successfully, so what?
>
> > > > > "So what" is that my data wasn't hooped by your brain-dead strategy of
> > > > > simply aborting on error, that's what. I know you don't think users'
> > > > > data actually *means* anything, but I can assure you, the *user* thinks
> > > > > it does.
>
> > > > Sorry, I didn't say lose data. I said you can't continue working
> > > > as nothing happened after that. "Recovery code will be able to run
> > > > successfully", right. Now read what you snipped, and *then* argue
>
> > > "recovery" includes saving data and terminating.
>
> > So do it? Who said you shouldn't it? You can save data
> > and terminate. But you ought to terminate, with saving
> > or not, if you use glib.
>
> what? glib only crashes sometimes?

It rarely crashes, indeed. What are you talking about?

> you don't *have* to terminate. You could free some memory.
> Or abort some operation. On large long running systems
> you don't die just because the user can't display the current
> alarm list

So you write the application in a different way. Gtk
toolkit is not for such an application (not for the
application which leaks so much that it runs out of
memory on the long run).

>
> > That's it. But I am told that
> > an application can do more. No it can't.
>
> sometimes it can.

Sometimes yes. Who objects?

>
> > If the main loop
> > can't push an event onto the event queue, then you're
> > screwed.
>
> yes, that's a bit extreme. But if it's comoing from an external
> source you could discard it and wait for the repeat.

There won't be repeat.

> > No "application performs worse" or "some parts
> > are not working".
>
> I think you are mistaken.
>
> > (Note, it is not about all applications,
> > don't talk about failsafe mp3 players or about webservers,
> > those simply shouldn't use glib)
>
> so what class of application should? Games? Mobile radio Systems?
> Database servers?

Desktop applications.

Yevgen

Malcolm McLean

unread,
Jan 29, 2008, 10:30:01 AM1/29/08
to

"Nick Keighley" <nick_keigh...@hotmail.com> wrote in message

On 29 Jan, 09:23, ymunt...@gmail.com wrote:

>> Except where you got a bug. In the place you won't
>> test.
>
>sorry, you must have missed "You ALWAYS test the return from malloc()"
>

You're mixing up execute with fork. Your policy is to always fork on every
call to malloc(). The question is, do you then execute both branches of the
fork in every debug run?

It is loading more messages.
0 new messages