Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: fmt: don't recover panics except for dereferencing nil fmt.Stringer receivers #28150

Open
bcmills opened this issue Oct 11, 2018 · 8 comments

Comments

Projects
None yet
5 participants
@bcmills
Copy link
Member

commented Oct 11, 2018

When a type passed to a fmt function implements fmt.Stringer, the fmt package recovers any panics that the String method produces.

That's helpful for the common case of nil pointers (https://play.golang.org/p/YbmlVGcfPvO), but in other cases masks real, important bugs — and can lead to unexpected deadlocks (https://play.golang.org/p/GjOv8M75GqG; see also #25245).

I propose that, for Go 2, the fmt package should only recover a panic from a fmt.Stringer if:

  • the value underlying the fmt.Stringer is a nil value of a pointer type, and
  • the panic occurred as a result of dereferencing the receiver (not due to an explicit panic call or a dereference of some other value).

Enforcing the latter condition may require deeper runtime support.

@bcmills bcmills added this to the Go2 milestone Oct 11, 2018

@bcmills bcmills changed the title proposal: Go 2: fmt: don't recover panics except for nil `fmt.Stringer` receivers proposal: Go 2: fmt: don't recover panics except for dereferencing nil fmt.Stringer receivers Oct 11, 2018

@robpike

This comment has been minimized.

Copy link
Contributor

commented Oct 11, 2018

The fmt package tries hard to do something always. The idea is that if you're printing something, and there's a problem, the problem is likely due to code that hasn't run before and/or is hard to get to run at all, so it's better to print something than crash or return error.

I'd like to keep it that way. It's worth not crashing a program because a log statement has a bad argument, for example. I admit this can cause problems sometimes, but all decisions do, and your proposal adds complexity and removes utility in the aid of relatively rare cases. The tradeoff doesn't feel right.

@bcmills

This comment has been minimized.

Copy link
Member Author

commented Oct 25, 2018

The idea is that if you're printing something, and there's a problem, the problem is likely due to code that hasn't run before and/or is hard to get to run at all, so it's better to print something than crash or return error.

If the problem is “due to code that hasn't run before and/or is hard to get to run at all,” that seems to make it even more important to preserve the stack trace that led to it — which is exactly the information that recover destroys.

@bcmills

This comment has been minimized.

Copy link
Member Author

commented Oct 25, 2018

The recover in fmt is especially insidious because — unlike the recover added for #28242 — it does not result in a user-visible error.

(Users often omit error checks for fmt calls, and even if they did check, the fmt functions don't return an error on panic anyway: https://play.golang.org/p/x92v-MWuzPF)

@robpike

This comment has been minimized.

Copy link
Contributor

commented Oct 25, 2018

If the problem is “due to code that hasn't run before and/or is hard to get to run at all,” that seems to make it even more important to preserve the stack trace that led to it — which is exactly the information that recover destroys.

I know what you're trying to say, but I disagree. I'd rather see bogus output from a rare log statement than crash a production job.

I do not want to change this behavior in the fmt package.

@mvdan

This comment has been minimized.

Copy link
Member

commented Nov 16, 2018

Also worth noting that text/template now recovers panics encountered while calling template functions: #28242

One of the big points in favor was that fmt did something very similar. So if fmt changes in Go2, perhaps other pieces of the standard library like text/template should be reconsidered too.

There's one big difference, however. If fmt recovers a panic, it can be easy for it to go unnoticed, whereas Template.Execute will simply return the recovered panic as an error. That should be much more obvious.

@mvdan

This comment has been minimized.

Copy link
Member

commented Jan 29, 2019

I just realised that my last comment was completely redundant given @bcmills' earlier comment; apologies for not reading the thread properly.

@nhooyr

This comment has been minimized.

Copy link
Contributor

commented Feb 9, 2019

Why don't we make fmt show the stack trace as well instead of just the panic value? That would be a reasonable middle ground.

@nhooyr

This comment has been minimized.

Copy link
Contributor

commented Feb 9, 2019

E.g. this code (https://play.golang.org/p/g0_AlCKKOa3) right now produces

%!s(PANIC=runtime error: invalid memory address or nil pointer dereference)

Along with the error message, it'd include a full stack trace to make it easier to debug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.