Decorating exceptions with backtrace information

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Decorating exceptions with backtrace information

Ben Gamari-3

Hi everyone,

After a nice discussion on IRC about the unfortunate state of error
reporting in Haskell, I felt compelled to write down some long-lingering
thoughts regarding backtraces on exceptions. The result is GHC proposal
#330 [1]. I think the approach is viable and perhaps even
straightforward. I have the sketch of an implementation here [2].

Please have a look at the proposal and leave your comments. If there is
consensus it is possible that we could have this done for 8.12.

Cheers,

- Ben


[1] https://github.com/ghc-proposals/ghc-proposals/pull/330
[2] https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3236

_______________________________________________
Glasgow-haskell-users mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users

signature.asc (497 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Haskell-cafe] Decorating exceptions with backtrace information

Henning Thielemann

On Fri, 8 May 2020, Niklas Hamb├╝chen wrote:

> On 5/8/20 5:37 PM, Henning Thielemann wrote:
>
>> a callstack is not useful for a user.
>
> Call stacks have been very useful to me as a user of non-Haskell tools
> so far, because they are excellent for attaching to bug reports and
> usually led to developers fixing my problems faster.

This confirms that they are not for you, but you only forward them to the
developer.


Can someone please give me examples where current state lacks and how they
are addressed by the proposal(s)?
_______________________________________________
Glasgow-haskell-users mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users
Reply | Threaded
Open this post in threaded view
|

Re: Decorating exceptions with backtrace information

Ben Gamari-3
In reply to this post by Ben Gamari-3
Michael Sloan <[hidden email]> writes:

> Thanks so much for making a proposal for this, Ben!!  It's great to see
> progress here.
>
> I'm also glad that there is now a proposal process.  I made a fairly
> similar proposal almost exactly 5 years ago to the libraries list -
> https://mail.haskell.org/pipermail/libraries/2015-April/025471.html - but
> without the subtlety of particular backtrace representations.  Skimming the
> ensuing thread may still be informative.
>
Thanks for the reference, Michael! My feeling is that the proposal in
that thread is a bit too dynamic. That being said, I can see the
argument for wanting, for instance, a robust way to determine that an
exception is asynchronous.

> In particular, there is one thing I would like to highlight from that old
> proposal.  I think it'd be good to have a standard way to represent a chain
> of exceptions, and build this into `catch` and `finally`.  Python and Java
> both have a mechanism for this, and both refer to it as a "cause"
> exception.  When an exception is thrown during exception handling, the
> exception being handled is preserved as its "cause".  I find this mechanism
> to be incredibly useful in Java, it has made the underlying issue much
> clearer in many cases, and in other cases at least provides helpful
> context.  I have no doubt such a mechanism would have saved me many hours
> of debugging exceptions in Haskell systems I've worked on in the past.
>
> I considered commenting about that directly on the proposal, but I figure
> this is a better place to suggest expanding the scope of the change :) .
> Totally understandable if you want to keep this proposal focused on
> stacktraces, but I think it'd be good to consider this as a potential
> future improvement.
>
Indeed I can see the point. I'll keep this point in the back of my mind.
I'm not eager to further expand the scope of the proposal at the moment,
but we should be certain that the backtrace design doesn't
unintentionally close the door to this use-case.

However, one question I would have is whether the exception-chaining
use-case *needs* to be handled in SomeException. For instance, you could
rather leave this to user code. You might even give this pattern a
typeclass. For instance,

    class HasChainedException e where
        getChainedException :: e -> Maybe SomeException

    data MyException = MyException { causedBy :: SomeException }

    instance HasChainedException MyException where
        getChainedException = causedBy

Cheers,

- Ben

_______________________________________________
Glasgow-haskell-users mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users

signature.asc (497 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Haskell-cafe] Decorating exceptions with backtrace information

Henning Thielemann
In reply to this post by Henning Thielemann

On Fri, 8 May 2020, Ben Gamari wrote:

> Henning Thielemann <[hidden email]> writes:
>
>> We are talking about the HasCallStack stack traces, yes?
>> How is their emission addressed by extending exceptions with stack
>> traces?
>
> HasCallStack stack traces are one type of backtrace that the proposal
> supports. However, it's not the only (nor is it even the most useful
> sort, in my opinion).
>
> Other mechanisms include cost center stacks from the cost-center
> profiler and native stack unwinding.


Interesting. That's a completely new thing.


>>> * Developers cannot easily produce stack traces do debug unintended
>>> exceptions.
>>
>> What are "unintended exceptions"?
>> What is an example of an "unintended exception"?
>
> For instance,
>
> * Somewhere deep in my code a colleague used `fromJust` due to a
>   miscommunicated invariant

That's a programming error.

> * Somewhere in my system a `writeFile "tmp" $ repeat 'a'` failed due to
>   filling the disk

Hm, that's also a programming error, but it ends in an IO exception. If it
would not end in an IO exception (e.g. writing to /dev/null) it would go
to an infinite loop. Anyway, it is a programming error. However it is an
unchecked one. That is, there is no warranty that you can catch it by a
debugger. So I do not think you can achieve much with callstacks here.

> * Somewhere in my system I have a partial pattern match in a module
>   which was compiled without -Wall

Programming error and btw. before thinking about a GHC extension I would
enable -Wall ...

> * Somewhere in my system I `div` by zero due to lack of input
>   validation

Programming error

> * I use a record selector on a sum.

Programming error

> * A logic error results in an assertion failure deep in my program, but
>   it's unclear which path my program took to arrive at the assertion

Sounds like Programming error


> This list could go on and on...

From your list of examples I deduce that the proposal is about programming
errors. But we have HasCallStack for that one. How does the proposal
improve or alter the HasCallStack solution? And how does it relate to the
IO exception system with hierarchical exceptions and SomeException and so
on?


> Currently the proposal does not cover asynchronous exceptions but it
> wouldn't be particularly hard to extend it in this direction. This would
> allow far better reporting of heap/stack overflows and MVar deadlocks
> (which are particularly hard to debug at the moment).

Hm, what kind of heap or stack overflow are you thinking of?

A stack overflow sounds like unlimited recursion and thus like a
programming error. In contrast to that, a program must be prepared for a
failure of "malloc". Memory exhaustion is an IO exception, it should be
explicit in the type.

Are MVar deadlocks always detected by the runtime system?
_______________________________________________
Glasgow-haskell-users mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users
Reply | Threaded
Open this post in threaded view
|

Re: [Haskell-cafe] Decorating exceptions with backtrace information

Ben Franksen
Am 12.05.20 um 23:29 schrieb Henning Thielemann:
> A stack overflow sounds like unlimited recursion and thus like a
> programming error.

Perhaps it was just one recursion to many? Computer memory is limited.
Heap overflow is also quite possible even with a program that is
provably terminating. I have used 'ulimit -v' in the past to force ghc
to fail rather than having to reboot my machine :-/

> In contrast to that, a program must be prepared for a
> failure of "malloc".

I don't see any essential difference between allocation by the runtime
and explicit allocation using malloc. I think this is a good thing that
in Haskell you /can/ recover from such a condition.

> Memory exhaustion is an IO exception, it should be
> explicit in the type.

Then it must be explicit in all types, since in general all computations
may exhaust the available memory. And then what use would that type
information have?

> Are MVar deadlocks always detected by the runtime system?

My guess is that deadlock detection in general is undecidable i.e. with
more than one MVar present, but I may be wrong about that.

Cheers
Ben

_______________________________________________
Glasgow-haskell-users mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users