Investigate if error handler can be made to return
The rigraph error handler immediately calls error() (an R API functions), which I believe escapes to the R top level immediately through a longjump.
https://github.com/igraph/rigraph/blob/dev/tools/stimulus/rinterface.c.in#L2300
In other interfaces (Python, Mathematica), the error handler returns normally and allows the error code to propagate to the top, where it can be handled. This issue is a reminder to investigate if the same can be done in R.
Why is it better for the error handler to return? Because this is necessary in order to free all memory when integrating igraph with some other libraries. A typical case is a library that uses callback functions. We want to use igraph's error handling mechanism in the callback function. This means that the error handler may be called from the callback. If the callback is not allowed to returned to the caller library, some resources in that library may not get cleaned up.
Note that igraph integrates several libraries, such as GLPK, Bliss, Cliquer, etc. where this can be a problem.
It is also a problem with Bison-based parsers, where we want to be able to handle errors in Bison actions. I made this work properly for the Pajek parser but it relies on the error handler returning normally.
Note to self: R's own error() function does a longjmp() so the only way to achieve this goal is to only store the error message in the error handler and then check for it later when we return from igraph-land to R-land. We have an R_igraph_finalizer function, which is apparently called every time when we do so, so we can probably raise the error there instead.
What if there is more than one error message? This happens occasionally, especially at library boundaries, when there may be one error in the callback and another error when the library returns to igraph.
Does R have any means to separate message printing from aborting on error? Or can they only be done at the same time with error()?
Maybe the messages can be collected and concatenated, then passed to error() at the very end.
This could work as long as we don't call back to R from C (e.g., in attribute handlers or callbacks). If we do, the R code could call error() on its own, which will longjmp(). I have recently added R_igraph_safe_eval() as an alternative to R's own Rf_eval() API in C (which is often simply referred to as eval() or EVAL()), so if we can find and identify all places in the code of the R interface where we call back to R from C and replace the eval() calls with R_igraph_safe_eval(), then we can proceed with collecting errors and raising them at the very end. But right now there are hard crashes and other issues to fix so I'd consider this as low priority (too much work for too little gain).
Instead of collecting errors, would it not be better to print them right away with REprintf()?
Note: this must be done before upgrading to the 0.10 C core because of changes to error handling in that version (ENTER/EXIT). Memory is not guaranteed to be freed unless the error handler returns. Hence the 2.0 milestone.
Note to ourselves: a key problem here is that we have lots of hand-written code in the R interface that assumes that igraph's error handler will longjmp() -- that's why none of the calls to igraph functions are wrapped in IGRAPH_CHECK() or something similar anywhere in the R interface. So, if we want to make igraph's error handler return normally, we will also need to go through all the hand-written code and also the generated bits, and make sure that we have a wrapper around igraph function calls that checks the return value and does not proceed with the execution if the error code is not IGRAPH_SUCCESS.
@krlmlr I think this is done. Re-open if there's anything left to do.