xmalloc string functions

K

Kelsey Bjarnason

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?
 
K

Kelsey Bjarnason

[snips]

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.
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.
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.
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.
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.
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.
... 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.
 
K

Kelsey Bjarnason

[snips]

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.

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.

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.
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.
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.
 
B

Ben Bacarisse

Malcolm McLean said:
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.
 
R

Richard

Randy Howard said:
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.
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.
 
R

Richard

Yevgen Muntyan said:
Kelsey said:
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
 
P

Paul Hsieh

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.
 
F

Flash Gordon

Yevgen Muntyan wrote, On 28/01/08 04:17:
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.
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.
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.
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.
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.
 
F

Flash Gordon

Malcolm McLean wrote, On 28/01/08 09:21:

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.
 
C

CBFalconer

Kelsey said:
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. :)

Too late. I already did. :)
 
C

CBFalconer

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

No, I suggest this is not a toy example. At most it requires
replacing sizeof with "N * sizeof".
 
D

dj3vande

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
 
Y

ymuntyan

Yevgen Muntyan wrote, On 28/01/08 04:17:





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.

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.
That is part of the normal design process.


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.
Yes, this is called software design, a task that people writing software
should perform.


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.
I'm sure that William does know.





Do you have reason to believe that the X server is that brain dead?

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"?
William has suggested *not* pretending nothing happened.


Right, he didn't suggest anything.
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?
The rest of the code still wants memory.
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).
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
 
Y

ymuntyan

[snips]

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.
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.
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".
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.



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.
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.
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.
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
 
R

Richard Heathfield

Kelsey Bjarnason said:
[snips]

On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
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>
 
D

dj3vande

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?

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.


dave
 
W

William Ahern

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.
 
Y

ymuntyan

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.

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.

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
 
Y

ymuntyan

[snips]

On Mon, 28 Jan 2008 15:53:59 -0800, ymuntyan wrote:
[snip]
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
 
Y

ymuntyan

Kelsey Bjarnason said:
On Mon, 28 Jan 2008 04:17:54 +0000, Yevgen Muntyan wrote:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top