[GRASS-dev] Vect_*_fatal_error()

Glynn Clements glynn at gclements.plus.com
Mon Nov 14 15:53:38 EST 2011


Sören Gebbert wrote:

> i respect the G_fatal_error() design decision and i think it is a very
> good decision for a C based library which should be used to implement
> processing modules. What puzzles me is, that interactive vector
> digitizing is IMHO hard to implement using this design decision.

It's only a problem if fatal errors actually occur. Sanitising user
input may help with this.

The Python community has the terms EAFP and LBYL, acronyms for "Easier
to Ask for Forgiveness than Permission" and "Look Before You Leap"
respectively. EAFP describes the try-except idiom, where you ensure
that code deals with errors, while LBYL refers to validating inputs to
ensure that errors don't occur in the first place.

GRASS' "fatal" error concept makes EAFP problematic, so some degree of
LBYL is essential for a persistent application.

> As Glynn stated you will face unexpected behavior when forcing
> G_fatal_error() not exiting, because of the not existing memory
> management/error handling in the library design after a
> G_fatal_error() call.

Actually, "unexpected behaviour" is a problem with longjmp()ing out of
a fatal error handler. If you were to just allow the error handler to
return, the behaviour would be much more straightforward: you'll get a
segfault when you dereference the null pointer which was the reason
for signalling a fatal error in the first place. Or when you try to
read pointers or array indices from uninitialised memory (where the
failure of whichever function was supposed to initialise it was the
reason for the fatal error).

If you don't want fatal errors, you'll have to re-write the libraries
not to use G_fatal_error(). Just making G_fatal_error() itself return
isn't going to achieve anything useful.

> IMHO one solution is to keep editing functions in the vector library
> G_fatal_error() free, implementing a robust error handling and memory
> management for such functions.

The main problem with this is that it clutters up the code. Normally,
I'd suggest still calling G_fatal_error(), but performing any
necessary clean-up beforehand, based upon the assumption that the
process will be using setjmp/longjmp to recover from the error.

Except .. that's going to need some support, as you can't use setjmp()
directly from Python (the jmp_buf becomes invalid once you return from
the function which "called" setjmp()). We would need something like:

	static jmp_buf jbuf;

	static void the_handler(void *unused)
	{
	    longjmp(jbuf, 1);
	}

	void *G_safe_execute(void *(*func)(void *), void *closure)
	{
	    G_add_error_handler(the_handler, NULL);
	    if (setjmp(jbuf) == 0) {
	        G_remove_error_handler(the_handler, NULL);
	        return (*func)(closure);
	    }
	    else {
	        G_remove_error_handler(the_handler, NULL);
	        return NULL;
	    }
	}

> The next point is to have a separate vector digitizing process for the
> wxGUI digitizer. How should this work? Using RPC to have access to the
> vector library in wx C++ code? Implementing special editing modules
> ...  which make vector editing IMHO very slow?

No. Just make the digitiser a separate process which imports
grass.lib.vector etc. If it crashes, you just lose the digitiser
rather than losing the entire GUI.

Using RPC in Python is quite straightforward with the "pickle" module,
but I don't think that it would help much. A fatal error in the RPC
server will kill the RPC server; having the client survive only helps
if it can recover from that.

-- 
Glynn Clements <glynn at gclements.plus.com>


More information about the grass-dev mailing list