Jeffrey Stedfast wrote, On 03/02/08 19:35:
but later you say there are no one-size-fits-all solutions?
That particular part of it is a common element that can be reused where
appropriate
If the toolkit being used is not one of those, then it is irrelevant that
some provide a means to do so, particularly if the "some" are not
available for the platform being targeted.
You can always go straight to the X API or the Windows API or whatever
for the emergency code.
I never said "badly designed", though I would agree "sub optimal in an
ideal world". There's a difference (to me, at least).
There is a whole range of design quality, and it is not even a line more
of a space with several dimensions. Perhaps I should have said "badly
designed in this respect" since in other respects they might approach
perfection.
There was meant to be an if in there. As in, "However, it it has enough
memory to do it.
I'll agree with that, and wherever I use malloc() directly (or
g_try_malloc(), I do write error handling - which may or may not include
attempting popping up an error dialog depending on the situation).
Well, that is good
Right, but as you mentioned was a problem for xmalloc(), we have the same
problem here. Not enough context for most real-world applications to
recover at this point.
OK, yes, but if you override the malloc/calloc/free when running your
emergency recovery code you can use your pre-allocated block for the
allocations that Gtk+ does so avoiding further out-of-memory problems
Easier said than done, not that it /can't/ be done - but one could easily
argue that this is more effort than it is worth, and unless you are able
to test your failure cases thoroughly, not even reliable.
As with all of life there are tradeoffs to be had.
It is /more/ reliable to routinely auto-save the user's work (as you
mentioned elsewhere, to a file other than the original) because it is
much easier to warn users about problems (potential or no) and certainly
easier to implement recovery should the application crash due to
uncontrollable (kernel crash, power outage, etc) error conditions on the
next application startup.
I agreed that this can be part of your recovery strategy.
Depending on the document, one could write the application such that any
button click (or whatever) would cause an auto-save in addition to some
timeout, thus reducing the likelihood of there being any unsaved changes
at any given point in time.
Or do what some editors I used to use did and literally save all changes
as the user went along. This was saving in to a recovery file not over
the original, and one recovery file would cover all the work done to all
files in that session. The best was the one where you could literally
sit watching it retype everything...
Since you obviously need this auto-save functionality in place if you are
serious about protecting the user's data at all costs anyway, then it
becomes no longer necessary to chain malloc() failures up your call stack
in order to use static emergency buffers.
At this point g_malloc() calling abort() becomes a moot point,
particularly if your auto-save code is robust against memory allocation
errors (keeping a small subsection of code bug free and robust against
all possible error conditions is a lot easier and less costly in
developer time than it is to do that for an application several million
lines of code long).
You should *still* do your damnedest to pop up a dialogue box so the
user knows the crash is due to out-of-memory! Also you want the program
to exit using exit not abort otherwise files might not be flushed before
being closed. Especially important of you use the method I just
suggested of logging everything as you go along rather than an autosave.
Hey, guess what? Evolution did this using an auto-save approach and it
used g_malloc() in much of the application code.
Well, I didn't like evolution anyway, I found it was hogging too many
resources on this machine for not enough benefit ;-)
Different approaches, same end result. Oh, sure, maybe in your ideal
case, the application exits from main() with a 'return 0;' as opposed to
an exit() call (or abort()), but that is irrelevant.
[snip]
You probably need mechanisms to signal the spell checker and print
process anyway to cope with the user choosing to abort them.
This is true, however you still need context information in order to do
so. I never said that the application wouldn't have the ability to cancel
the spell checker or printing, but in order to do so you need context. If
you are in a function being called asyncronously from somewhere which
might not even be your code which may not pass up your particular error
condition, then you are pretty much screwed unless your contexts are all
globally accessible.
Such things are likely to be separate threads, so you just send them an
appropriate signal (not necessarily in the C sense of the word) and give
them a chance to terminate. Then you only need to know how to signal
them which is information you could make globally available (maybe by
exposing a "kill print job" API that keeps static state).
While this may suggest the application (or the libs it depends on) is
poorly designed (or at least not suitably designed), the argument does
little to solve the actual problem at hand.
There are ways.
In the real world of end-user software development (e.g. not software
written for space ships or other areas where human lives are on the line)
Um, those *are* real world situations! ;-)
where the application's design is based on incomplete specifications (as
in they tend to change mid-development)
That applies to SW written for space ships and SW where lives are at
stake as well. Although such things do tend to be better documented and
change controlled.
in combination with insufficient
allotted time,
That certainly applies in the defence industry where I spent 15 years :-/
designing the perfect solution is downright impossible,
Well, nothing is ever perfect!
and so it is, unfortunately, not all too uncommon for the application's
design to be insufficient for every possible error condition.
If this is new to you, then you've never written real-world software and
I would appreciate having your pitty... because I, too, would love to
live in Ideal World where I have sufficient time and specifications to
use in order to come up with a proper design before I'm forced to begin
implementation
In the real world when asked to reduce an estimate I've been known to
sit and think for a few minutes and then say...
"Well, in my opinion you don't really need these pieces of functionality
since the things they are there for can be said to be covered by these
other things, and so by removing these requirements you remove this
amount of work."
I didn't get any complaints about my response either. I was the expert
and they had to accept my word on it.
[snip]
That it depends on the daemon shows that is is possible, or it would be
a simple case that none do.
Normally they report something the system administrator is able to
understand. At least, most that I use do.
Key word: most
The others *could* and not doing so is another aspect of poor quality.
Also a reason I would consider switching to an alternative.
Agreed in so much as they are not an ideal solution to the failing malloc
problem
Well, that is a start
They are, however, /a/ solution to the problem and might, in some
situations, be more than ample.
Better than dereferencing a null pointer. An application specific
alternative is better than a general purpose one as it can do
application-specific clean-up that a generic wrapper can't.
As have I, in my gui applications even.
So yours aren't all bad ;-)
In an ideal world, perhaps. If you've already got an auto-save feature
then it is not necessarily worth the extra effort.
I would agree that it /is/ worth the effort in the case where the failing
malloc() call is in the auto-save code, however
So you aren't as bad as some
I would conclude, that, like some parts of Evolution, if it is unable to
allocate resources for some non-critical data structure(s), that it is
able to report the "out of memory" issue to the user.
I seem to recall you claiming VMWare reported "out of memory" conditions
to the user as well, but as Ben Pfaff noted, VMWare uses xmalloc-like
wrappers as well.
It was some king of out-of-resource, and as it was less than a month ago
I've not had it happen again to check exactly what the error message is ;-)
OK
Sure, the same goes for any application written on top of glib!
So don't write it on top of glib ;-)
(Not the case if you use g_malloc() of course, but you are hardly forced
to use only g_malloc() just because you link with glib).
Only if none of the other bits you call use g_malloc.
Not necessarily, but I will agree that this is /likely/ the case.
If you attempt to allocate the space on creating the document it is
*definitely* the case that the user will not have had a chance to do
anything with it.
I've used this approach for some simpler applications.
Auto-save is actually not that much different to this.
The logging has the advantage of never having to open a new file to it
after application start up, and generally all the resources needed to
write to a file are allocated when you open it
Amusing to me is that none of these developers are writing GUI apps or
libs afaict ;-)
Well, I do it occasionally.
It's not hard to find command-line programs and/or general purpose libs
that /are/ robust, like Ben Pfaff's AVL tree library for example, but
none of the ones I know of for writing GUI applications are of this
quality.
If I wanted to write an application that would meet your ideal criteria,
I'd have to write my application from the ground up, including the widget
toolkit. This is not only impractical from the development standpoint,
but also from the user's perspective where the application does not look
like any of his other applications. It would also not be able to share
much with the other applications running on the user's desktop and so
would use a lot more resources than a Good Enough solution.
Of course, you could work on improving the toolkits to deal with the
problem ;-)
Equally, if I had the time I could.
Anyone using glib stand-alone should probably reconsider, especially if
they are writing "mission critical" applications.
Most people, however, use glib via Gtk+ - and being that is the /only/
practical widget toolkit available to C software developers for Unix, you
can't easily write off glib altogether.
There where widget sets around before the start of the GNOME project and
they have been used successfully.
I honestly would not be surprised if the other major contender in the
widget toolkit space (being Qt) had similar problems wrt memory
allocation failure conditions, but even if it did, you wouldn't be able
to write the application in C afaik (you'd have to switch to c++).
Or write the GUI front end in C++ and the rest in C. Or do the GUI front
end in C# or Java or...
Yes, this is what I've been saying.
So you don't call glib functions from within that code
Glad we agree so far.
Well, discussing it here isn't going to get the problem solved. If you
truly feel that strongly about it, then you should either fix the problem
(free software, afterall) or at the very least submit a bug report! ;-)
Oh that I had the time to bug-hunt free SW. Unfortunately I only
occasionally have time to bug-hunt the free libraries I use in the SW my
company sells and definitely don't have the time for other free SW. When
I do have the time I do submit bug reports and/or bug fixes.
You /assume/ that all code paths properly handle OOM conditions
internally and propagate them back up the call stack. But libc is still
only implemented by humans last I checked, so there is a possibility of
bugs.
Yes, and therefore it is pretty much guaranteed that all libc
implementations have bugs somewhere. I would, however, expect the memory
allocation functions to be amongst the most hammered and hence least
buggy parts of the library.
That's a pretty hefty assumption that you CANNOT rely on for mission
critical user data (since that's what your whole argument revolves around
in the g_malloc()-is-evil argument).
It is an evil that could have been avoided.
Because of this possibility, you MUST implement a safety net - aka auto-
save. Once you have auto-save in place and properly written to handle
every conceivable error condition that /it/ may encounter (OOM being
one), then the value gained by using malloc() over g_malloc() in the
remaining areas of the code begins to rapidly lose their practical value
(if the goal is simply to make sure the user's data is saved before
exiting).
Wouldn't you agree?
Personally I would still be likely to switch to a (possibly commercial)
application if I hit crashes on out-of-memory if they did not inform me
they that they were shutting down due to out-of-memory. If they let me
know I am a bit more tolerant as long as the recovery on restart gets
back my work.
OK, *I* always have the choice, even if sometimes it involves changing
job. Not had to go that far yet though
For bonus reading, you might check out Richard Gabriel's paper on Worse
Is Better.
GLib's g_malloc() must be "good enough" because more and more Gtk+
applications keep popping up like wildfire just as C overtook LISP due to
the Worse Is Better rule.
What becomes popular is not always determined by what is good. There are
many examples of the worse solution winning out.
Personally I would seriously consider using a language that supports
exception handling if error propagation was going to prove too hard to
be "worth the effort". This would mean switching from C, but I consider
a language to be merely a tool so switching is not a problem.
As to LISP, I never liked it, but that is not an argument for here.