Re: Exception-Handling in C




"Bruce W. Bigby" <bbigby@rochester.rr.com> writes:

> "Bruce W. Bigby" wrote:
> > 
> > Hi, all. I just wanted to let people know that I've been sitting on an
> > exception-handling package for the C programming language that I began
> > about 5 years ago but recently updated to be thread-safe, etc. I also
> > wrote an article about it in the November 1998 issue of Dr. Dobb's
> > Journal. It would solve the problem where GNOME does not support true
> > exception-handling. I'd also like some people to read the man pages and
> > give it a whirl. It would be a shame to waste my efforts and the efforts
> > of the kind sole who ported it to DOS for me. In any case, please take a
> > look at http://home.rochester.rr.com/GEF/GEF.html. The software follows
> > the LGPL.
> > 
> > Later,
> > --
> > Bruce W. Bigby
> > http://home.rochester.rr.com/bigbyofrocny
> > Do for others what you would want others to do for you.
> 
> Sorry for the typo. That's
> http://home.rochester.rr.com/bigbyofrocny/GEF/GEF.html.

This probably is not the best list for discussing this issue - 
gnome-list is basically about user-level issues, not developer
level issues. gnome-devel-list would be a more suitable
forum.

The issue of setjmp/longjmp based exception handling has come
up various times for the GLib library. (Development of GLib
is dicussed on gtk-devel-list@redhat.com). I (and I think
most of the other developers) have generally not been to
keen on the idea.

The problems I have with it are:

 - The lack of stack-cleanup facilities in C means that you
   code written to be exception safe must include far more
   try {} blocks than it would in C++, Java, etc.

   In fact, writing exception-safe code in C++ is often a 
   matter of keeping all state in stack objects with destructors.

 - Throwing across non-exception-safe code is a BAD idea.
   Memory leaks are one obvious bad consequence, but worse,
   you may well corrupt internal state. For instance,
   throwing an exception inside a GTK+ signal handler and
   catching it outside would be pretty much guarantee
   a segfault next time you used the signal system.

   If you are using 3rd party C libraries, you will have
   to worry about exception-unsafe code. Which means 
   putting try {} blocks around every callback and then
   trying to do something sensible when you catch an
   exception in one of those try blocks.

 - If you want to work with other exception handling systems
   (C++, Python, CORBA, etc.) then you have to take care
   to catch exceptions at the boundaries and convert them.
   Conversion is almost always lossy - since exception
   types seldom map from one to the other exactly.

What I'm trying to say with all of the above, is that writing
exception-safe code in C is a painful and very tedious
problem, and that clever setjmp/longjmp macros don't really
help much as compared to going CORBA-style and passing
extra parameters. In fact, IMO, they hurt because the
potential to throw exceptions is implicit and hidden from
the programmer. So you get code that seems to work until
you stress it. 

Of course, the point could be made "well, OK, so exceptions
wouldn't be 100% reliable, but wouldn't it be better than
printing out an error and aborting in any case?". I would
tend to say no. There is a great deal of extra complexity
a careful programmer would have to add into all code if we
introduced exceptions, and if a mechanism is available,
people should be able to use it without worrying that it 
is going to break 1% of the time, or knowing a big list
of places where they can't use it.

The GLib/GTK+ approach to error handling is:

 - If a routine can have a runtime error which can be usefully 
   handled by a application writer, then that error should be
   reflected in the API in terms of a return value.

 - If a routine encounters a runtime error that cannot 
   be handled by the programmer (that is, things are
   screwed up beyond all redemption), then it will log
   an error message and abort.

 - If a routine encounters an error that is due to programmer
   mistake (e.g. passing in NULL for an object pointer that
   can't be NULL), it logs as descriptive as possible a message 
   to the GLib logging mechanism and returns, returning
   a value indicating an error if the API provides for such.

This approach is not especially clean in a theoretical way,
but it does make for a very convenient API for the programmer,
and produces quite robust code. 

(Aside: Assuming people clean up the warnings that their code
produces - people - if your program produces a ***Gtk-Critical:
warning, it is broken, and you should fix the warning before doing
anything else.)

In general, I like exceptions (though people sometimes get drawn
into the trap of assumming that a cryptic exception is better
than a verbose error message) - and use them when the facility
is available to me.

But I don't think that setjmp/longjmp exceptions work well when
incorporated into something as large and heterogeneous as
GTK+/Gnome/Glib, and they and especially CORBA-style exceptions are
just too painful for the programmer to be used extensively.

 GtkWidget *window = NULL;
 GtkWidget *button = NULL;

 TRY {
   window = gtk_window_new();
   button = gtk_button_new_with_label ("press_me");
   gtk_container_add (GTK_CONTAINER (window), button);
   gtk_widget_show (window);
 } CATCH(exception) {
   if (button)
     gtk_widget_destroy (button); 
   if (window)
     gtk_widget_destroy (window);
   THROW(exception);   
 }

===

 GtkWidget *window = NULL;
 GtkWidget *button = NULL;

 G_EXCEPTION_INIT (exception);
 window = gtk_window_new(exception);
 if (exception->type != G_EXCEPTION_NONE)
   goto error;

 button = gtk_button_new_with_label ("press_me", exception);
 if (exception->type != G_EXCEPTION_NONE)
   goto error;

 gtk_container_add (GTK_CONTAINER (window), button, exception);
 if (exception->type != G_EXCEPTION_NONE)
   goto error;

 gtk_widget_show (window);
 if (exception->type != G_EXCEPTION_NONE)
   goto error;

 return;

error:
 if (button)
   gtk_widget_destroy (button); 
 if (window)
   gtk_widget_destroy (window);

I've written a fair bit of exception-safe code in C and exception
thunking code for my Perl bindings for the ILU, MICO, and ORBit
CORBA ORBs, and it is never pleasant. It isn't something I would
want to inflict on ever GNOME library and application developer.

Regards,
                                        Owen
.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]