Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29009 Discussions

Traceback information when calling Fortran from C/C++

Darek
Beginner
4,604 Views

I have a Fortran static library project which is linked to C/C++ program (tried both, pure C and C++). My goal is to execute Fortran code from my C/C++ program and in case there is any error get the traceback information. I am using Visual Studio 2010 with Intel Visual Fortran Studio XE 2013 to build everything.

The problem is that when there is an error in the Fortran code my program crash (which is fine), but I can't get the traceback. However, when I invoke my subroutines from a Fortran program (the main program is a Fortran code), then I get traceback information.

The Fortran static lib is compiled with the following parameters (just the most important): /debug:full /Od /traceback /check:bounds /check:stack /libs:static /threads /dbglibs /c

I found in the documentation that I have to initialize the Fortran runtime library, so that Fortran error handlers are established. I added invocation of for_rtl_init_ in the main() of my C/C++ code, however this doesn't work. The documentation of the for_rtl_init_ subroutine says that it only assigns the Fortran error handlers for Linux and OS X. How can I do that for Windows?

0 Kudos
25 Replies
Steven_L_Intel1
Employee
3,636 Views

Is it that you get no traceback at all, or that the traceback is missing line number information? You can try building the C/C++ code with /Oy- which tells the compiler to use the EBP register as the stack pointer, which is necessary for proper operation of traceback. However, we don't really support traceback when used from a C/C++ main program. Intel C++ does have a /traceback option that adds the line number correlation information to the object, but this is meant for C/C++ code called from a Fortran main program.

With a non-Fortran main program, errors that are detected by the Fortran run-time library, such as I/O errors, will result in traceback, but hardware-detected errors such as access violation won't, as far as I know. (I have not tested this extensively.)

0 Kudos
Darek
Beginner
3,636 Views

I meant that I don't get any traceback at all.

In meantime I tried also setting the environment variables: FOR_DIAGNOSTIC_LOG_FILE=path_to_fortran_log_file and FOR_DISABLE_DIAGNOSTIC_DISPLAY=T, but it seems like it has the same result - works only for some errors (tested on accessing array element which is out of bounds, but no traceback for division by zero).

I will try to check whether the floating-point exception handling can produce a traceback which I can access and I will also check this /Oy compiler parameter.

But, basically from what you are saying is that with non-Fortran main program I can get the tracback information only for I/O errors? So if my Fortran code starts some computations in separate thread and this parrarel thread gets an error (like division by zero or array element out of bounds or any other exception), then I won't be able to get any information about it (when I am running the Fortran code from a non-Fortran main program)? 

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

I believe that is correct. Only a Fortran main program sets up a try-except block around the main program to catch such things. I suppose you could call TRACEBACKQQ from your C++ exception handler.

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Some added tips.

You can (and probably should) call for_rtl_init_ from the C++ code. While this won't allow Fortran to catch everything, it will help some.

Change the C++ project's Linker > General > Enable incremental linking to No. Incremental linking prevents traceback from finding the PC-line number correlation information.

0 Kudos
Darek
Beginner
3,636 Views

I think I almost solve the problem. I added my own try-except block for the calls from C++ to Fortran. In the C++ exception handler am I invoking the Fortran TRACEBACKQQ subroutine. So if there's an exception that would terminate my program then I am able to get information about it.

The problem I have now is that my C++ is code is in fact a DLL which is a part of bigger system. It is run as a Windows service and when needed the C++ DLL is loaded and Fortran code is executed. The Windows service doesn't have its own console so I am creating one (AllocConsole) and assinging handlers for stdout and stderr. This works fine - I can get all the standard output and standard error from my .NET managed, C++ unmanaged and Fortran code. The problem is with TRACEBACKQQ (called directly or by the Fortran runtime). The output from this subroutine doesn't go to stdout or stderr (or maybe I can't read it?). If I start my C++ as a console application, then I can see the output from TRACEBACKQQ in the console window. So how do you send characters to OS? Is there any way to redirect it (especially the output from TRACEBACKQQ)? Does TRACEBACKQQ use standard newline characters (CHAR(13) // CHAR(10))?

The only way that works for me is to set the FOR_DIAGNOSTIC_LOG_FILE=path_to_fortran_log_file and FOR_DISABLE_DIAGNOSTIC_DISPLAY=T environment variables and redirect the whole TRACEBACKQQ output to a file, but I would like to avoid this solution.

Any chance I could get the output of TRACEBACKQQ without setting those environment variables?

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

As far as I know, the traceback goes to stderr. There is no control over this other than the environment variables

0 Kudos
Frank_F_
Beginner
3,636 Views

I am working under Windows OS and I am using the FORTRAN compiler version 2011.9.300 integrated in the MS Visual Studio 2010. The solution prepared by Darek is working: FORTRAN exceptions like "subscript out of range", FORTRAN IO errors or integer divisions by zero are now caught by the C++ managed code environment and the traceback information is written to the output file.

But floating point errors are still missing and cannot be caught. E.g. a division by zero forced by a a floating variable "0.0f" results in a "NaN" or in an "Infinity" value but can not be handled by the managed code try/ catch block (also no traceback information is written). These floating point errors seems to be handled somehow separately. And this handling seems to be independent on the selected FORTRAN floating point exception handling compiler option.

The question which I have is: how can floating point exceptions be covered by this solutions (catching the floating point exceptions and generation of traceback information)?

Thank you!

Frank

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Frank, try adding a call to for_rtl_init_ at the start of your program and see if that helps. It can be in a Fortran routine you call at the program start, or you can call it from the C++ (as unmanaged code).

0 Kudos
Frank_F_
Beginner
3,636 Views

Steve, thank you for answering.

"for_rtl_init()" is already called in my example. It does not help and makes no differences for handling of the floating point errors.

Calculating the division by zero on floating variables in a managed code DLL project always leads to a infinite value (no matter what I set in the Floating Point compiler section). But having a standalone Fortran program and using the floating point option /fpe:0 produces an exception and the traceback for "division by zero" for floating variables.

What else can I do?

 Frank

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Can you attach a ZIP of a sample solution that demonstrates the problem? I'd like to try it myself to see what is happening.

0 Kudos
Frank_F_
Beginner
3,636 Views

Steve, the uploaded ZIP archive contains the examples projects.

Call the procedure "Open TestProject.cmd" top open the solution. The solution file contains the following projects:

  1. TestLib: FORTRAN static library, contains the FORTRAN file Simulation2.F90 that forces the error (floating divide by zero). Contains also the traceback handler (file TRACEBACK.F90)
  2. CSCTestWrapperNew: C++ managed code wrapper DLL, class

    Managed2FortranWrapper::FortranWrapper::simulation contains the try/ catch block and calls the FORTRAN subroutine (Simulation2() though subroutine Simulation())

  3. TestConsoleAppManaged: C# console application calls the wrapper DLL "CSCTestWrapperNew", thiswrapper then calls the FORTRAN subroutines

  4. FortranConsole: FORTRAN console application project calls directly the FORTRAN subroutine

    Simulation2() that forces the error

Currently the error "floating  devide by zero" is forced. While the FortranConsole application produces an error, the TestConsoleAppManaged is running without any error. Debugging shows that an "Infinite" value is produced. This is independent on the FORTRAN compiler option selected in category  "Floating Point" / "Flaoting Point exception handling"

Please change in file Subroutine2.F90 variables from floating to integer types. Now both application projects (FortranConsole  and estConsoleAppManaged) are producing an error.

Frank

 

 

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Frank, the missing piece here is that your Fortran library is not establishing the FP exception environment. This happens with the Fortran console application, where you have set /fpe0, and that causes a call to FOR_SET_FPE to be made from the main program. When you invoke the Fortran code from C#/C++, this never happens.

There are two ways to get what you want. The easiest way is to add /fpe-all:0 under Fortran > Command Line > Additional Options in the Fortran library project. This causes every Fortran routine to call FOR_SET_FPE at the start. (I note that you have a "/debug inline-debug-info" in this property - it's missing a colon after /debug).

The other way is to call FOR_SET_FPE explicitly from your Fortran or C++ code. This is easier to do in Fortran as the IFCORE module provides all the declarations of the options, but you could call it from C++ if you copied those in.

With either of these changes, I get:

[plain]
loading test Fortran subroutines...
 Fortran2 stderr: Computing the result...
 Fortran2 stdout: Computing the result...
 starting computation...
in filter section, code: -1073741131
Stack trace from Fortran runtime.

Image              PC        Routine            Line        Source
CSCTestWrapperNew  0F823C0D  _SIMULATION2               20  Simulation2.f90
CSCTestWrapperNew  0F823A9A  _simulation                60  Traceback.f90
clr.dll            56632A17  Unknown               Unknown  Unknown
clr.dll            56632B09  Unknown               Unknown  Unknown
clr.dll            56632672  Unknown               Unknown  Unknown
clr.dll            5664264F  Unknown               Unknown  Unknown
clr.dll            56642E97  Unknown               Unknown  Unknown
clr.dll            566EC82C  Unknown               Unknown  Unknown
clr.dll            566EC950  Unknown               Unknown  Unknown
clr.dll            5676D9EC  Unknown               Unknown  Unknown
clr.dll            5676DA8F  Unknown               Unknown  Unknown
clr.dll            5676DBA2  Unknown               Unknown  Unknown
clr.dll            5676F92A  Unknown               Unknown  Unknown
mscoreei.dll       70C9F5A3  Unknown               Unknown  Unknown
MSCOREE.DLL        70D17F16  Unknown               Unknown  Unknown
MSCOREE.DLL        70D14DE3  Unknown               Unknown  Unknown
ntdll.dll          77749EF2  Unknown               Unknown  Unknown
ntdll.dll          77749EC5  Unknown               Unknown  Unknown
[/plain]

which I think is what you want.  Right?

There's some additional discussion of this general topic at http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/9ff547c0-c250-451c-a58f-90b4f1696ea7/

0 Kudos
Frank_F_
Beginner
3,636 Views

Steve,

yes, this is the missing piece. This is what we want to have and it works.

Thank you very much,

Frank

0 Kudos
Frank_F_
Beginner
3,636 Views

I am still using the solution described here for exception handling in a mixed C#, C++, FORTRAN managed/ unmanaged code application.

Up to now I had called the FORTRAN subroutines only one time before stopping the application. Now I am trying to call the same FORTRAN subroutines a second time through the managed code (C#- calls C++-, C++- calls FORTRAN-functions). In case the traceback and exception handler is active the program crashes always with a "System.AccessViolationException" error. When disabling the exception handling the program finishes normally without any visible exception.

The question I have is: why gets the application much more sensitive regarding exceptions in case the exception handler is active compared to the case it is inactive? I would expact the same kind of exceptions but no further exception information in case the handler is inactive?

Secondly I got no further information about the detail reasons of the crash: the calling stack points somewhere to the handling and conversion of strings:

  ntdll.dll!RtlIntegerToUnicodeString()  + 0x2fc bytes [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
  ntdll.dll!RtlIntegerToUnicodeString()  + 0x20b bytes 
  libifcoremdd.dll!__for_ieee_set_rounding_mode_()  + 0x38f bytes 
  libifcoremdd.dll!for_lge_ssll()  + 0xdbc bytes 
  libifcoremdd.dll!for_open()  + 0x3c3 bytes

Why is this error occuring only for the seond call of the same FORTRAN function (the input data is the exactly the same)?

Is there anywhere another post which handles this issue and where I can obtain more information how to solve it?

Thank you!

 Frank

 

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Frank, when you get errors such as access violation on a second or subsequent call, that strongly suggests that you have a calling convention mismatch. How do you have the Fortran routines declared in C++? Which compiler options are you using in Fortran and are you using ATTRIBUTES STDCALL anywhere?

0 Kudos
Frank_F_
Beginner
3,636 Views

Steve, yes we are using the STDCALL calling convention, here is an example how it is declared in C++:

extern "C"

{int __stdcall SM_WRITE_MPM(int *ret, void * g);}

The FORTRAN Compiler options we are using are: CVF (/iface:cvf). This seems to be the mismatch between C++ and FORTRAN which I have to correct!

Which calling convention do you recommend for the managed/ unmanaged code environment?

Frank

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

If you are using /iface:cvf, then you are getting STDCALL so there is no inconsistency.

0 Kudos
Frank_F_
Beginner
3,636 Views

Steve,

I still could not solve the problem described above (12/18/2013): when calling FORTRAN subroutines a second time the program crashes with a "System.AccessViolationException" error.

I think I could provide a simple test application to demonstrate the problem. Would it be then possible for you to check the program?

Thank you!

Frank

0 Kudos
Steven_L_Intel1
Employee
3,636 Views

Yes, I can look at a test application. You can attach a ZIP to a reply here.

0 Kudos
Frank_F_
Beginner
3,512 Views

Steve,

this is the test program to demonstrate the unsolved system access violation when calling a FORTRAN subroutine a second or subsequent time.

The application consist of 4 projects:

1. Managed code C# console application: project "ConsoleAppManaged". Here in the main program 2 times the FORTRAN wrapper is called .
2. Unmanaged C++ Wrapper of the FORTRAN subroutine: project "FortranWrapper"
3. Fortran project "Fortranlib": here the only FORTRAN function "SM_OPEN_FILE.FOR" is prepared which just opens an existing file "Test.dat". The Fortran function is compiled with command line option "/fpe-all:0"
4. Project "FortranExceptionHandling": here only the traceback output is prepared

When running the console application the program crashes in FORTRAN "OPEN" instruction when it is called a second time (refer FORTRAN function SM_FILE_OPEN.FOR, line 87).

But this happens only as long as the "__try"/ "__catch" block in C++ wrapper code (file Managed2FortranWrapper.cpp, method "FortranWrapper::ExecuteFortran()", line 69ff) is active. When this try/ catch block is commented out no crash can be detected.

What is the reason for getting the exceptions?

I am still using the Intel(R) Visual Fortran Composer XE 2011 Update 9 (Integration for Microsoft Visual Studio* 2010, 12.1.3526.2010).

Thank you very much!

Frank

0 Kudos
Reply