1

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?

kostmo
  • 6,222
  • 4
  • 40
  • 51
  • Can you qualify "best"? In general, stack traces don't make as much sense in a lazy functional language as you probably expect them to, so probably your "best" bet is to enable profiling. Otherwise, use [`CallStack`](https://hackage.haskell.org/package/base-4.10.0.0/docs/GHC-Stack.html). – user2407038 Aug 09 '17 at 00:01
  • I guess I would settle for any method that identifies the line in source code at which the error occurs. When you say enable profiling, does that mean I could run `stack build` with some extra parameters (which ones?), and then when I execute the program it will accompany the error with more information? – kostmo Aug 09 '17 at 00:31

1 Answers1

2

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.

Community
  • 1
  • 1
Rein Henrichs
  • 15,437
  • 1
  • 45
  • 55
  • In the latest GHC release, `error` *is* `errorWithCallStack`. And the docs seem to suggest you get better stack traces from a profiled build than using `HasCallStack`. I haven't tried the profiled way yet. – dfeuer Aug 09 '17 at 02:34
  • @dfeuer Do I understand the claim correctly that GHC 8.2.1 w/ `-prof` should produce better call stacks? It doesn't seem to be so: https://gist.github.com/TomMD/7d1fb8dc762fc37bf80b7b7dd447e29a – Thomas M. DuBuisson Aug 09 '17 at 04:45
  • Even with profiling enabled (via `stack build --profile`), I see only the error message "divide by zero" with no additional context. Let's say there is a codebase in which the division operation (`/` or `\`div\``) appears at dozens of call sites. When one encounters the error message "divide by zero" at runtime, and any of those call sites seem to be equally likely candidates as the source of error, how does one approach debugging? Must one swap out each instance of the division operation with some annotated version (at best, narrowing down the offending call sites in a binary search)? – kostmo Aug 09 '17 at 04:46
  • @ThomasM.DuBuisson, I really don't know, but take a look at https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#compared-with-other-sources-of-stack-traces – dfeuer Aug 09 '17 at 06:31
  • I don't see any such implication there. – Thomas M. DuBuisson Aug 09 '17 at 13:33
  • 1
    @ThomasM.DuBuisson `-prof` with `-fprof-auto` or manually added SCC annotations make more descriptive callstacks. – Li-yao Xia Aug 10 '17 at 14:48
  • Indeed. While it doesn't retain/print the entire stack it does yield the final function that actually calls error. Useful. – Thomas M. DuBuisson Aug 10 '17 at 18:14