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