Catching fortran runtime errors and signals in C++ binding

609 Views Asked by At

I would like to be able to catch a terminating Fortran runtime errors in a C++ binding. I have a legacy F90 code to bind to and expect all kind of errors e.g. numerical, IO etc.

I managed to handle STOP according to: Intercepting Fortran STOP from C++ and able to throw/catch exception for this case in the C++ code.

I got some understanding 'Signal Handling in Fortran' at https://www.sharcnet.ca/help/images/4/42/Fortran_Signal_Handling.pdf

However I do not manage with this, an example for f90 fortran would be very helpful.

For example trying to open a non existant file in the fortran subroutine would give a runtime error, and the C++ code terminates:

open (unit=13,FILE="fnameBAD",status="old",action="read",position="rewind")

Fortran runtime error: Cannot open file 'fnameBAD': No such file or directory

I would like to be able to catch this and other runtime errors using signals.

2

There are 2 best solutions below

0
janneb On

This won't work, at least for GFortran. When then OPEN statement fails, the GFortran runtime library will shut itself down, and only finally is the signal generated. So by the time you can catch the signal in the signal handler, libgfortran has already shut itself down (including closing all open files).

The solution, as Vladimir F says in a comment, is to catch the error in the OPEN statement with the iostat= specifier.

0
dev-zero On

I've implemented something like that for unittesting C-bindings for a Fortran code from C/C++ to catch abort calls using setjmp and longjmp (essentially the same as an answer in the already linked question):

#include <setjmp.h>
#include <signal.h>

jmp_buf jmp_env;

void on_sigabrt(int signum)
{
    (void) signum; // silence "unused parameter" warning
    longjmp(jmp_env, 1);
}

void func()
{
    if (setjmp(jmp_env) == 0) {
        signal(SIGABRT, &on_sigabrt);
        /* YOUR CALLS HERE */
    } else {
        /* ERROR HANDLING GOES HERE */
    }
}

The problem @janneb already described remains: Even while longjmp should restore the stack to the point of the setjmp, it does not guarantee that all internal state in the Fortran runtime library is restored.

In fact, both books Modern Fortran: Style and Usage (rule 182) and The Fortran 2003 Handbook (15.6.4) mention that Fortran code should not be wrapped in between setjmp and longjmp.

On the other hand, there are compiler vendors which explicitly provide setjmp/longjmp wrappers (Oracle for example), as well as several projects with a similar focus:

That being said, it is likely a better (and more portable) approach to use proper error handling using the iostat attribute whenever possible, as others already commented.