Hi all
We have had this discussion in the past. But I would like to reopen it.

We really really need to get id of the exit() calls in PLplot. I don't
think that we can really make any recommendation that our library is
"industrial strength" while they are their and I would be very nervous
about using PLplot in production software with them in - plus even
using PLplot for science work I have been caught out be these calls in
the past.

I think there are a few options we have got

Firstly with our internal propagation we can either do
A1) Set up our functions so they return error codes and make sure we
check these. I feel there is a tendency for this to be bad because I
know that I am inherently lazy if I am frank (and I'm sure we all have
our lazy moments) and tend to write code without these checks then
(try to) go back and add them later. Missing checks are likely to
cause segfaults or memory corruptions which are even worse than the
exit calls().

A2) Set up an error flag in PLStream which can be set on error and
checked after every function call. This would avoid having to change
functions that already return values, but still relies on manual
checks which I think will be a big weak point.

A3) Use setjmp/longjmp calls. In this case we call setjmp in the top
level of every API call and on error we call longjmp which returns the
execution point back to the point setjmp was called. There is some
extra setup time here to avoid memory leaks and other resource leaks,
but once that is done we can all write code with almost no worry
regarding error propagation.

Once we decide on our internal method we need to decide how we can
inform the user. We have a number of options again:

B1) An API change so that all our functions return an error code.

B2) Make use of our current plabort call and let the user pass in a
plabort handler.

B3) If we have an error, store an error code in PLStream and add an
API function called plgeterr or similar which allows the user to check
for error after any other function call.

B4) In the C++ binding we could throw an error. Not sure if other
languages have similar throw/catch style options.

B4) Some combination of the above.

I will add there are some specific things we need to think about for
our C++ drivers. These are not so much options, but things we need to
deal with anyway.

C1) Our C++ drivers cannot be allowed to throw an error out of the
driver code and into the main C code. That would potentially end up
with the throw going all the way out to the user's top level code
which may be in C, Fortran, or any other language that can't deal with
it. Note that even if the driver doesn't call throw, it may call
either something in the stl or another driver (in Qt or wxWidgets for
example) that does throw. This is easy to avoid by wrapping the intry
points in try blocks. I have done this for wxWidgets, but haven't
checked the other C++ drivers to see if they are the same.

C2) If we go for option A3, then we cannot allow longjmp over C++
code. This is because nontrivial destructors are not called when
longjmp is called and if objects with these destructors are jumped
over then the result is undefined behaviour - which again is worse
than exit calls.

The fix for C2 - and I think this would be a good thing anyway - would
be to have a specific driver API. This would allow us to have setjmp
calls when we enter that API and avoid jumping over drivers. I think
this would be nice in general as it is not well documented how to
write a driver and a proper driver API would address that.

I am well aware that the use of setjmp and longjmp is very divisive.
So my intention is to work this code up only for the case of memory
allocation failures. This code will consist of:
D2)A set of plmalloc, plrealloc and plfree fuctions which will replace
the usual versions. As well as allocating/freeing memory these
functions will record the allocations in the PLstream.
D1)PLTRY, PLENDTRY macros which will go in each API call. PLTRY will
have the setjmp call. This will be followed by the current code in the
function as it is now then PLENDTRY will deal with what happens if
longjmp has been called - it will check for memory allocations
recorded in the PLStream and will free them. For now it will then just
call exit() so we get the same behaviour but this can be changed later
if we want to go down this route. Once we have this first look at how
setjmp/longjmp can work in our code then I think it will be easier for
us to make an informed choice about the A options.

Does that sound sensible to people? If anyone would like to look at
what would be involved in doing a similar thing using the other
options then it would be really nice to be able to compare the work
and admin/code practices needed for those too.

Phil

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Plplot-devel mailing list
Plplot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/plplot-devel

Reply via email to