1

Haskell プログラムで使用している外部 dll があります。いくつかの特定のケースでは、dll がクラッシュします。

簡略化: まず、メソッド A にいくつかのパラメーターを指定して dll に送信し、次にメソッド B を呼び出してそれらのパラメーターに対していくつかの計算を行う必要があります。十分なパラメーターを指定しなかった場合、MethodB は dll 全体をクラッシュさせます。この場合、Haskell アプリケーションもクラッシュします。

これを処理する方法はありますか?残念ながら、dll からスローされる例外はありません。

ghci で次のメッセージが表示されます: InitNumericalSystem::initializeSystem でエラーが発生しました。ジャンクレーベル。

「catchAny を使用しようとしましたが、役に立ちませんでした。c_run は、4 つの入力パラメーターを受け取る外部 dll メソッドです。

catchAny :: IO a -> (SomeException -> IO a) -> IO a
catchAny = Control.Exception.catch

main :: IO ()
main = do
  let timeTot = []::[CDouble]
      timeNow = []::[CDouble]
      runType = 2::CInt
  timeTotPtr <- newArray timeTot
  timeNowPtr <- newArray timeNow
  result <- (catchAny $ c_run timeTotPtr runType timeNowPtr 0) $ \e -> do
    putStrLn $ "Got an exception: " ++ show e
    putStrLn "Returning dummy value of -1"
    return (-1)
  free timeTotPtr 
  free timeNowPtr 
  print result

編集: withAsync でも試してみましたが、運が悪くて tryAny :: IO a -> IO (Either SomeException a) tryAny action = withAsync action waitCatch

catchAny :: IO a -> (SomeException -> IO a) -> IO a
catchAny action onE = tryAny action >>= either onE return

try2 :: IO ()
try2 = do
      let timeTot = []::[CDouble]
          timeNow = []::[CDouble]
          runType = 2::CInt
      timeTotPtr <- newArray timeTot
      timeNowPtr <- newArray timeNow
      putStrLn $ "c_run going to call c_run.."
      result <- catchAny (c_run timeTotPtr runType timeNowPtr 0) (const $ return (-1))
      free timeTotPtr
      free timeNowPtr
      putStrLn $ "Result: " ++ show result
4

1 に答える 1

3

Haskell から DLL 内の関数を呼び出す場合、DLL がプロセスのアドレス空間をいじるのを防ぐセーフティ ネットはありません。ここに 3 つのオプションがあります。

  • DLL に適切な API が含まれている場合、問題が発生する前に呼び出しが成功するかどうかを判断できます。これらの条件を Haskell の型システムで表現することで、「適切な使用」を強制することもできます。この方法では、Haskell コードをコンパイルするときに、DLL からのランタイム クラッシュも発生しません。
  • 最後の呼び出しでエラーが発生したかどうかを確認する関数を DLL が提供することは珍しくありません。たぶん、あなたはこの方向を探りたいと思うでしょう。
  • 「クラッシュ」とは、呼び出しがセグメンテーション違反などを引き起こすことを意味する場合、Haskell / GHC / ランタイムがそれに対してできることはあまりありません。メイン プロセスから生成された別のプロセスから DLL への呼び出しを実行することで、問題を切り分けることができます。これは明らかに、子プロセスを生成してデータを渡すためのパフォーマンス コストをもたらします。
于 2013-09-23T16:32:10.057 に答える