Opened 3 years ago

Last modified 9 months ago

#11829 new bug

C++ does not catch exceptions when used with Haskell-main and linked by ghc

Reported by: pl Owned by:
Priority: normal Milestone:
Component: Runtime System Version: 7.10.3
Keywords: c++ exceptions Cc: pl, simonmar, basvandijk
Operating System: MacOS X Architecture: Unknown/Multiple
Type of failure: Runtime crash Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Consider the C++ program

// Main_cc.cc
#include <iostream>
#include <exception>
extern "C" {
int func() {
  try {
    throw std::runtime_error("THIS FAILS!");
  } catch(const std::runtime_error &c) {
    std::cerr << c.what();
  }
  return 0;
}
}

and the Haskell program

-- Main.hs
module Main where
import Foreign.C.Types
foreign import ccall func :: IO CInt
main :: IO ()
main = print =<< func

When compiled with

ghc --make Main.hs Main_cc.cc -lstdc++

and being run on mac os x 10.11.3 the result is

libc++abi.dylib: terminating with uncaught exception of type std::runtime_error: THIS FAILS!
Abort trap: 6

and not (as it should be):

THIS FAILS!0

When compiled in a similar way under windows some c++ exceptions of a larger project are not caught as well. However, these were hard to track down and I was unable to construct a simple example like the one above.

As a workaround one can

  • write a main() function in c++ and call from there into Haskell,
  • compile the Haskell-Module with the options "-c -no-hs-main", and
  • link the application using g++ (not ghc!).

When being compiled / linked this way, all c++ exceptions are being caught in mac os x as well as under windows.

Change History (5)

comment:1 Changed 3 years ago by thomie

Operating System: Unknown/MultipleMacOS X

Nice testcase. Works fine on Linux though.

comment:2 Changed 2 years ago by mtolly

This is still the case on macOS 10.12.5 and GHC 8.0.2. By examining the ld call from g++ and experimenting, I discovered the fix is a flag that Clang's linker needs. Place this in the cabal file executable section:

ld-options: -lto_library

Or use the following flag for GHC:

ghc (source files) -lstdc++ -optl-lto_library

In the cabal file this amusingly parses the flag wrong and produces the incorrect advice:

Warning: Instead of 'ld-options: -lto_library' use 'extra-libraries: to_library'

and it also prints the message from #5019 for some reason:

ld: warning: could not create compact unwind for _ffi_call_unix64: does not use RBP or RSP based frame

Here is some info on what the flag does, but I don't quite understand how it is connected to exceptions. And this page suggests that a newer Clang will supply the flag automatically.

comment:3 Changed 14 months ago by syntheorem

I just ran into this, but the -lto_library flag didn't fix the problem (Clang is passing it automatically now anyway). What ultimately worked for me was adding -Wl,-keep_dwarf_unwind to my ld-options.

I tried your method of writing main in C++ and manually linking via Clang to see what it does. Interestingly, just linking against the Haskell libraries and RTS with no other flags broke exceptions for me. But I also got the same warning:

ld: warning: could not create compact unwind for _ffi_call_unix64: does not use RBP or RSP based frame

I searched for that and discovered that you could use -Wl,-no_compact_unwind to disable the warning; and GHC already passes that flag to Clang during linking. But that option also somehow breaks the exception handling tables; the system will fall back on the DWARF exception tables if you include them by passing -Wl,-keep_dwarf_unwind.

Also worth noting that I'm on macOS 10.12.6, which is about a year out of date, so the issue might be fixed on the most recent version. Using GHC 8.4.3 and Clang 6.0.1.

comment:4 Changed 9 months ago by basvandijk

As explained on GHC-devs I ran into this in our haskell-opencv library. I can confirm that adding the following to the cabal file of my minimal isolated test-case fixes the problem:

if os(darwin)
  ld-options: -Wl,-keep_dwarf_unwind

Shouldn't GHC pass these options by default when linking on OS X?

comment:5 Changed 9 months ago by basvandijk

Cc: basvandijk added
Note: See TracTickets for help on using tickets.