Stéphane Mottelet
Stéphane Mottelet

Reputation: 3014

Problem of exception catching in conda toolchain c++ -> fortran -> c++ (clang/gfortran)

I have different (but not satisfactory) behavior when trying to catch exceptions raised by a c++ function which is called by a fortran subroutine, itself called by a c++ main. The fortran subroutine in testf.f source file is:

      subroutine testf(simul)
      external simul
      call simul(0)
      end

and the c++ part (main and function) is in main.cpp source file:

#include <iostream>
using namespace std;

typedef void (*fun_t)(int *ind);
extern "C" void testf_(fun_t);
void cppsimul(int *i);

int main() {
    cout << "in main\n";
    try
    {
        testf_(cppsimul);        
    }
    catch (int e)
    {
        cout << "Caught exception\n";
    }
  return 0;
}

void cppsimul(int *i)
{
    cout << "in cppsimul\n";
    throw 0;
}

Linux x86_64, gcc/gfortran

When compiled with a pure gnu toolchain (g++ (Ubuntu 9.4.0-1ubuntu1~20.04.3) 9.4.0) under Linux/x86_64, I got the following result:

$ gfortran -c testf.f
$ g++  main.cpp testf.o -o main
$ ./main 
in main
in cppsimul
Caught exception

in fact the -fexceptions switch does not seem to be necessary.

macOS Sonoma x86_64, clang/gfortran

When compiled with a conda 24.7.1 toolchain (clang 18.1.4, gfortran 13.2.0), on a x86_64 mac, I get:

$ gfortran -c testf.f
$ clang++  main.cpp testf.o -o main
$ ./main
in main
in cppsimul
libc++abi: terminating due to uncaught exception of type int
zsh: abort      ./main
Caught exception

macOS Sonoma arm64, clang/gfortran

When compiled with a conda 24.7.1 toolchain (clang 18.1.4, gfortran 13.2.0), on a arm64 mac, I get:

$ gfortran -c testf.f
$ clang++  main.cpp testf.o -o main
$ ./main
in main
in cppsimul
zsh: trace trap  ./main

and when run in lldb I have the following trace:

in main
in cppsimul
Process 88839 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x18e794944)
    frame #0: 0x000000018e794944 libunwind.dylib`libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_arm64>::step(bool) + 504
libunwind.dylib`libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_arm64>::step:
->  0x18e794944 <+504>: brk    #0xc471
    0x18e794948 <+508>: pacib  x16, x8
    0x18e79494c <+512>: b      0x18e794a84               ; <+824>
    0x18e794950 <+516>: mov    x0, #0x0
Target 0: (main) stopped.

For both architectures, I have a normal output (the reference is Linux above) if I replace clang++ by /usr/bin/clang++ but it has no sense to do this for a bigger project (Apple /usr/bin/clang++ has version 15.0.0, from command line tools 15.1) as all dependencies of conda packages have versions which are compatible with the toolchain (clang 18.1.4).

What could be the problem with the conda toolchain? Probably a mismatch between system's /usr/lib/libc++ and conda libc++, but how could it be, as builds of conda packages are supposed to be coherent with each-other and with the system libraries.

I would be grateful if an expert could give be some explanations.

Upvotes: -1

Views: 105

Answers (1)

Artyom
Artyom

Reputation: 31271

Fortran and C do not support exception. You C++ function throwing an exception leads to undefined behavior.

Create a wrapper of this function in C++ that returns a error code and catches the exceptions internally.

This is the way C++ and C/Fortran can cooperate.

The fact that some compilers can handle it in non-standard way does not mean it is something universal or supported.

Upvotes: 1

Related Questions