如何在Haskell中找到浮点异常?

时间:2016-09-07 03:11:49

标签: debugging haskell

假设一个大而复杂的Haskell程序在执行期间的某个时间产生NaN。如何在不花费大量时间在我的代码中添加大量NaN检查的情况下找到我的代码中的哪个位置?我只对调试感兴趣,所以我不关心可移植性或性能。

这是五年前在Haskell-cafe上讨论过的。提出了一种可能的解决方案,但没有进一步讨论。 https://mail.haskell.org/pipermail/haskell-cafe/2011-May/091858.html

下面是我尝试使用AccessToken.getCurrentAccessToken().getPermissions() 按照Haskell-cafe讨论中的建议将堆栈跟踪到达生成NaN的点(在一个小示例程序中):

feenableexcept

不幸的是,运行此代码不会产生堆栈跟踪:(

-- https://www.gnu.org/software/libc/manual/html_node/Control-Functions.html
foreign import ccall "feenableexcept" enableFloatException :: Int -> IO Int

allFloatExceptions :: Int
allFloatExceptions = 1 {-INVALID-} + 4 {-DIVBYZERO-} + 8 {-OVERFLOW-} + 16 {-UNDERFLOW-}

main :: IO ()
main = do
  _ <- enableFloatException allFloatExceptions

  print $ (0/0 :: Double)

我假设(但实际上不知道)我没有得到堆栈跟踪,因为当异常中止程序时GHC运行时不受控制。接下来我尝试使用$ ghc -rtsopts -prof -fprof-auto testNaN.hs && ./testNaN +RTS -xc [1 of 1] Compiling Main ( testNaN.hs, testNaN.o ) Linking testNaN ... Floating point exception (core dumped) 中的installHandler来尝试使程序在GHC的运行时崩溃:

System.Posix.Signals

不幸的是,这会导致更神秘的错误,但仍然没有给我一个堆栈跟踪:(

import qualified System.Posix.Signals as Signals

-- https://www.gnu.org/software/libc/manual/html_node/Control-Functions.html
foreign import ccall "feenableexcept" enableFloatException :: Int -> IO Int

allFloatExceptions :: Int
allFloatExceptions = 1 {-INVALID-} + 4 {-DIVBYZERO-} + 8 {-OVERFLOW-} + 16 {-UNDERFLOW-}

catchFloatException :: IO ()
catchFloatException = error "print stack trace?"

main :: IO ()
main = do
  _ <- enableFloatException allFloatExceptions
  _ <- Signals.installHandler Signals.floatingPointException (Signals.Catch catchFloatException) Nothing

  print $ (0/0 :: Double)

我也试过使用多个线程。大部分时间都会发生以下情况。

$ ghc -rtsopts -prof -fprof-auto testNaN.hs && ./testNaN +RTS -xc
[1 of 1] Compiling Main             ( testNaN.hs, testNaN.o )
Linking testNaN ...
testNaN: too many pending signals

虽然,一旦发生这种情况。 http://pastebin.com/u3u2cnHE

我采取了正确的方法吗?有没有办法修改我的示例,以便我可以获得堆栈跟踪?

0 个答案:

没有答案