How to generate a stack trace upon division by zero with ghc 7.10.3?

573 Views Asked by At

If a program is run and crashes with the message "Divide by zero", what is the best way to identify where in the code this error was generated?

1

There are 1 best solutions below

7
Rein Henrichs On

GHC doesn't support stack traces as such because there isn't a call stack. The best you can do is to use the simulated stack trace machinery in the base module GHC.Stack.

Starting with GHC 7.8, and thus available in 7.10.3, GHC.Stack exposes

errorWithStackTrace :: String -> a

which acts like error on normal builds but uses the SCC annotations (e.g., from --fprof-auto) to construct an approximate stack trace on profiled builds. You will need to recompile with profiling enabled to support this. If you are using cabal, you can run

cabal configure --enable-library-profiling --enable-executable-profiling

and rebuild.

Starting with GHC 8.0, errorWithStackTrace is deprecated and support for call-site generation is provided by the HasCallStack machinery.

Quoting now from the GHC.Stack documentation,

A function can request its call-site with the HasCallStack constraint. For example, we can define

errorWithCallStack :: HasCallStack => String -> a

as a variant of error that will get its call-site. We can access the call-stack inside errorWithCallStack with callStack.

errorWithCallStack :: HasCallStack => String -> a
errorWithCallStack msg = error (msg ++ "n" ++ prettyCallStack callStack)

Thus, if we call errorWithCallStack we will get a formatted call-stack alongside our error message.

>>> errorWithCallStack "die"
*** Exception: die
CallStack (from HasCallStack):
  errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1

(I'm guessing msg ++ "\n" was meant, but "n" is what is written.)

While you can get some very limited stack trace support with GHC 7.8 and on, I would recommend upgrading to GHC 8 if possible for significantly better support. Either way, it won't be what you are used to from other languages, but it's better than nothing.