I have a Fortran DLL code that includes a lot of modules. The DLL is called by a C# code. I am trying to make the program exit gracefully without crashing if an error is encountered on the Fortran side. Also, I'd like to send error messages back to the C# side.
I am aware from some research that error trapping has been an issue between C# and Fortran. But, is there any update on that? Can the most recent compilers trap errors in Fortran between C# and Fortran?
There is no exception handling in Fortran. You may have options depending on what sort of error you want to trap. Some of them get raised and propagate normally, some get "handled" by the Fortran run-time library according to the severity and type.
Are you looking to trap ANY kind of error, or are there specific ones you are worried about? You should have a careful read of the section Handling Run-Time Errors in the Intel Fortran documentation.
I have no personal experience playing with this sort of thing. I would expect you'd have more success from processor-raised exceptions (floating overflow, etc.) and less from I/O errors. The link I provided is under Compiler Reference > Error Handling.
Intel Fortran does not create exception-propagating stack frames. I don't know well this will work for you.
The first good error trapping was continuations in LISP Compilers, which were an excellent idea. But the error trapping you see in C# is just not available in Fortran. LISP is perfect except that it is a turtle with speed and a beast to learn.
I do a lot of work in both -- but they are really not that compatible, they are close really -- but the error handling for C# is more like LISP Conts and Fortran just &^%*&
We have engineering programs with a C# GUI that call Fortran DLLs for the calculations. In the C# code, I put the call to the Fortran subroutine inside a try-catch block that catches any un-caught errors in the Fortran. In the Fortran subroutines, we've included if-statements to check for errors, such as division by zero, square-root of negative values, etc. before doing the calculation. If such an error is found by our if-statements we exit the routine, deallocate local arrays, and return an integer error code and string with a useful message back to the C# code to display to the user. The user can then hopefully understand what input to change and then run the analysis again. By deallocating local arrays in the Fortran DLL on exit, the user can re-run after changing the input data without needing to exit the program. This approach does require adding if-statements to check data before an error might occur, but this has worked well for us.
Regards, Greg T.
Yes that is the perfect soln - the only problem is catching all the error types -- there is always one you missed.
But that is also the difference between commercial and academic code -- we can cheat
I am just about to finish a similar project. I will provide some of the lessons I learned.
Firstly, I link my FORTRAN code with native C++ to generate a static library. Then I wrap the static library in a C++/CLI code. Calls between C# and CLI are managed calls. You can pass any info between like you are within C#. I uploaded here in this forum my project architecture sometimes ago.
1) I do not do anything fancy with memory on the FORTRAN side. If I need play with memory, I do it in C++. You can pass std::vector structures to FORTRAN safely.
2) I turned on the Intel Compiler option to check all subroutine parameters. I forgot how I did it but Steve may be able point out again.
3) I do not do any fancy I/O in FORTRAN.
Since things like division by zero do not produce exceptions (in the sense that FORTRAN generated code continues with "Nan" value), you can check them at a later point or even display it. I had no crashes in the last two years on the FORTRAN side. My initial problems were related to memory (mismatched commons) and incorrrect subroutine call list.
When I enabled the "Check for unallocated arrays" for Process-raised errors and an error takes place, I get an error message but the program crashes after I hit okay on the error message. Is there a way to gracefully exit the program after this kind of error takes place?
You should realise that using unallocated arrays is always an error in your program: you should allocate them first, before attempting to set an element or examine an element. The intrinsic function allocated() lets you determine if the array is allocated or not.
That said, just about the only thing that your program can do when it tries to do something else to an unallocated array is give up. Exceptions such as available in C# or other languages, allow you to jump to a completely different part of the program, but you cannot repair what went wrong either.
You need to solve the bug.
I was able to compile the C++/Fortran codes successfully for matrix multiplication and I added try-catch blocks in the C++ code. I'm still unable to figure out how to send the exception messages to C++ from fortran. For example, how can I pass an exception that there's a number being divided by zero or uninitiated variable?
The fortran code can detect them using Run-time error detection, but the fortran code stops working once these issues are detected without going back to the C++ code.
Oh,. what a merry chase you started me on...
The Intel documentation does have examples of SIGNALQQ and GETEXCEPTIONPTRSQQ. The examples don't work, the documentation is incomplete and has errors. I am sure that none of this has been looked at since the early days of DVF.
The section Using SIGNALQQ is most enlightening, in particular:
SIGNALQQ is just a Fortran jacket to the C run-time signal() function. When you call SIGNALQQ, you are actually registering your signal handler (or action) for a particular signal with the C run-time system. The C run-time system simply stores your handler (or action) in an internal exception action table or variable where it associates your handler with the desired signal. The operating system has no knowledge of this association.
As I wrote earlier, you can use SIGNALQQ to establish a handler for processor-detected errors such as floating point errors, but you can do that in C/C++ as well.
I am kicking myself, though, because I completely forgot about ESTABLISHQQ even though I am the one who designed it! This gives you a hook into both processor errors AND Fortran run-time library errors. What it doesn't do, though, is connect to C's SEH. Still, it may do something for you.
I have attached a working program, based on the manual's example, demonstrating SIGNALQQ and GETEXCEPTIONPTRSQQ. You must compile this with /fpe:0 or else you won't get the zerodivide. Do note that handling the zerodivide causes it to be retried, hence the STOP. This conflicts with the documentation and I am a bit puzzled by it (though it is reminiscent of VAX behavior on FP "faults".) One amusing thing is that the handler is a function that returns a value, but the documentation never describes this value and a C signal handler is a subroutine (void), no return value.
I will get around to submitting a ticket to Intel to see if they can correct the SIGNALQQ/GETEXCEPTIONPTRSQQ documentation and examples.
Thanks you. The code is working fine without using a C++ caller. The caller is the main program. I decided to do that as a start. I tried to replace the STOP by RETURN because I wanted the code to return to the main program after calling GETEXCEPTIONPTRSQQ. Is that possible?
As far as I know, that is not possible.
Fortran does have a set of features (the intrinsic modules IEEE_ARITHMETIC, IEEE_EXCEPTIONS, IEEE_FEATURES)that give you the ability to detect that a FP operation has failed and take action, but this isn't "exception handling". It also requires you to compile with /fp:strict. If you have a small set of operations that could be problematic, you could use the IEEE modules to deal with it, but it might be easier to just pretest the inputs before the operations.
Yes. See attached example.
D:\Projects>ifort /check t.f90 Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 22.214.171.124 Build 20200623 Copyright (C) 1985-2020 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 14.27.29111.0 Copyright (C) Microsoft Corporation. All rights reserved. -out:t.exe -subsystem:console t.obj D:\Projects>t.exe Exiting due to forrtl: severe (194): Run-Time Check Failure. The variable \'TEST$N\' is being used in \'D:\Projects\t.f90(11,1)\' without being defined