Segmentation Fault on First Fortran Runtime Library Error with C++ main()

Segmentation Fault on First Fortran Runtime Library Error with C++ main()

I have an application which has a C++ main() and which links in a Fortran library. We try to make sure that if a Fortran run-time library error occurs, the program has some way to report it. In the program below, the Fortran code delibrately causes a run-time error, but instead of printing the error and the traceback, something in the Fortran run-time library simply aborts. Here is the C++ main program (main.cpp):

extern "C" gen_error ( void );
int main( )
{
gen_error();

	}

and here is the Fortran part (gen_error.f90)

subroutine gen_error ( ) bind(c)
real, allocatable :: a(:)
allocate a(10)
allocate a(10) ! Can't allocate an allocated array
end subroutine gen_error

When I build this:

$ icc -c main.cpp
$ ifort -o main main.o -fexceptions gen_error.f90 -cxxlib
$ ./main
Segmentation fault

	

Running it under valgrind shows (in part):

==8722== Jump to the invalid address stated on the next line

	==8722==    at 0x0: ???

	==8722==    by 0x404FAD: for__issue_diagnostic (in /scratch/shared/src/main)

	==8722==    by 0x403269: for_alloc_allocatable (in /scratch/shared/src/main)

	==8722==    by 0x402C55: wha (in /scratch/shared/src/main)

	==8722==    by 0x402B5C: main (in /scratch/shared/src/main)

	==8722==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

	==8722==

	==8722==

	==8722== Process terminating with default action of signal 11 (SIGSEGV)

	==8722==  Bad permissions for mapped region at address 0x0

	==8722==    at 0x0: ???

	==8722==    by 0x404FAD: for__issue_diagnostic (in /scratch/shared/src/main)

	==8722==    by 0x403269: for_alloc_allocatable (in /scratch/shared/src/main)

	==8722==    by 0x402C55: wha (in /scratch/shared/src/main)

	==8722==    by 0x402B5C: main (in /scratch/shared/src/main)

	

It kind of looks like the run-time has not warmed up enough to emit the error message. Is there a Fortran run-time initialization routine we should be calling before entering the Fortran the first time from the C++ side?

This is with icc/ifort 12.1.2 20111128 on a CentOS 5.6 system with GCC 4.3.2.

Thanks,

Allen

Allen
publicaciones de 12 / 0 nuevos
Último envío
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.
Imagen de Steve Lionel (Intel)

Try compiling the Fortran code with -fexceptions And yes, you should call for_rtl_init_ from your C++ main program. Read about it in the Fortran documentation but generically:

for_rtl_init_ (&argc, argv);

Steve

Steve already answered, but since I had already prepared it, I'll post anyway.

Add a call to for_rtl_init_ in the C main and add -nofor-main -traceback to the ifort command-line.


extern "C" void gen_error ( void );

extern "C" void for_rtl_init_ (int *, char **);
int main( )

{

int argc;

char **argv;

for_rtl_init_ (&argc, argv);

gen_error();

}

 ifort -nofor-main -traceback -o main main.o -fexceptions gen_error.f90 -cxxlib 

That returns a call stack like:


$ ./main

forrtl: severe (151): allocatable array is already allocated

Image              PC                Routine            Line        Source

main               0000000000463B4A  Unknown               Unknown  Unknown

main               0000000000462646  Unknown               Unknown  Unknown

main               0000000000434EF0  Unknown               Unknown  Unknown

main               000000000041B25E  Unknown               Unknown  Unknown

main               000000000040650A  Unknown               Unknown  Unknown

main               0000000000402C45  gen_error                   4  gen_error.f90

main               0000000000402B47  Unknown               Unknown  Unknown

libc.so.6          000000389DC1ECDD  Unknown               Unknown  Unknown

main               0000000000402A49  Unknown               Unknown  Unknown

Great! That fixes my example problem. I'll try it out in my main code (if the cluster is ever available again :-).

Thanks,
Allen

Allen

Hi:
I guess there is still something I'm missing here. Adding a call to for_rtl_init to my real program does not stop the segmentation fault. The difference appears to be that my real program has a try/catch block surrounding the call which produces the Fortran run-time error. If I add a try/catch block to my example program:
[cpp]
extern "C" gen_error ( void );
int main( )
{
int argc;
char **argv;
for_rtl_init_ (&argc, argv);
try {
gen_error();
}
catch ( ... ) {
std::cout << "Caught an exception?" << std::endl;
}
}
[\cpp]
the program runs to completion, but it does not print "forrtl: severe (151): allocatable array is already allocated". Instead I get:
[plain]
$ icpc -fexceptions -c -g main.cpp
$ ifort -nofor-main -traceback -o main main.o -fexceptions gen_error.f90 -cxxlib
$ ./main
Caught an exception?
forrtl: severe (174): SIGSEGV, segmentation fault occurred
[\plain]
Also, in the absence of the print statement in the catch block, the program doesn't print anything at all.
I attached the valgrind output from running this program.
Thanks,
Allen

Adjuntos: 

AdjuntoTamaño
Descargar valgrind.txt13.65 KB
Allen
Imagen de Steve Lionel (Intel)

I'm not seeing any kind of segfault when I try your example. I get what Kevin showed.

I will comment that you won't be able to catch a Fortran-generated error in a try-catch block. In the next major release (second half of 2013) we're adding a method of "registering" a handler that gets called when a Fortran error is to be raised. -fexceptions simply allows exceptions generated in code called from Fortran to pass through Fortran frames.

Steve
Imagen de Steve Lionel (Intel)

I am going to guess that your actual Fortran code is different from what you posted above. Pretty easy guess, since what you posted won't compile as it is missing parentheses in the allocate statements. Please don't paraphrase or quote from memory - show us the actual code.

Steve

Hi Steve: I'm very sorry that my example wasn't better thought out. I have attached a tar file with a directory containing the exact code along with a Makefile and the output from the session. If I build the program and run it, I get no output. I ran my example under valgrind, too; it shows a lot of warnings about uninitialized variables and problems unwinding the stack (see valgrind.txt). This was built with ifort/icpc 12.1.2 on RHEL 6.3 with GCC 4.4.6 and GLIBC 2.12.

The tar file contains a typescript file with the output from my test (basically showing that no output is produced).

I tried this on windows with ifort 12.0.1.127 and cl 16.00.30319.01 (vs2010) and it actually works OK. It prints the "array is already allocated" message and the traceback.

I am not attempting to catch the Fortran runtime library error. In my real code, the Fortran periodically makes a callback into the C++. It's possible for that callback to throw an exception and that is what I'm trying to catch. Having the Fortran throw a catchable error would be great! But, all I want my current code to do is print the error and exit (i.e., call abort).

Thanks,
Allen

Adjuntos: 

AdjuntoTamaño
Descargar rt-error.tgz1.83 KB
Allen

Hi: We upgraded our linux compilers to icpc/ifort 13.0.1 20121010 and I still see the same behavior (i.e., nothing is written to the console). Are you able to reproduce my results or do I need to create a more realistic test case?
Thanks,
Allen

Allen
Imagen de Steve Lionel (Intel)

I can reproduce the no-output but I think what is happening is that your catch block is dismissing whatever error is occurring - and that's not the "already allocated" error which is not raised as an exception. If I add a printf there, it prints. I'm going to ask our library folks to take a look at it.

Steve
Imagen de Steve Lionel (Intel)

We found that the "stack unwind" code we were calling, part of a C library, "knew" that the main program was C++ and effectively disabled the Fortran traceback code.  We have found a workaround for this for a future release.

Steve
Imagen de Steve Lionel (Intel)

This should be resolved in the 14.0 compiler.

Steve

Inicie sesión para dejar un comentario.