Skip to content

Instantly share code, notes, and snippets.

@adamse
Created June 4, 2021 12:54
Show Gist options
  • Save adamse/0efecb95655eea287a4ec11967c76709 to your computer and use it in GitHub Desktop.
Save adamse/0efecb95655eea287a4ec11967c76709 to your computer and use it in GitHub Desktop.
FFI with exceptions
#include <stdio.h>
typedef void * CB(void);
void * u(CB * cb) {
printf("calling cb\n");
void* res = cb();
if (res != NULL) {
// exception
return res;
}
printf("cb success\n");
return NULL;
}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Exception
import Control.Concurrent
import Foreign.Ptr
import System.Exit
import System.IO
import Foreign.StablePtr
type CB = IO (Ptr ())
makeCB :: IO () -> CB
makeCB cb = catch act handle
where
handle :: SomeException -> IO (Ptr ())
handle e = do
ptr <- newStablePtr e
pure (castStablePtrToPtr ptr)
act = do
cb
pure nullPtr
foreign import ccall u :: FunPtr CB -> IO (Ptr ())
call :: IO (Ptr ()) -> IO ()
call ffi = do
res <- ffi
if res == nullPtr
then pure ()
else do
putStrLn "ffi exception"
exc :: SomeException <- deRefStablePtr (castPtrToStablePtr res)
throwIO exc
main = do
fbad <- funptr (makeCB bad)
fgood <- funptr (makeCB good)
call (u fgood)
call (u fbad)
foreign import ccall "wrapper" funptr :: IO (Ptr ()) -> IO (FunPtr (IO (Ptr ())))
good :: IO ()
good = do
putStrLn "OK"
bad :: IO ()
bad = do
ioError (userError "hej")
test: c.c HS.hs
ghc -c c.c
ghc -c HS.hs
ghc c.o HS.o -o test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment