-
Notifications
You must be signed in to change notification settings - Fork 18k
runtime: Goexit call will cancel a panic, which seems unexpected/incorrect #35378
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
Comments
I don't think that would be quite right. It would suppress the |
It does seem that a call to Anybody see a clear argument for a particular choice? |
Conceptually, I think either:
or
The former seems to be what happens today, so absent a strong argument to the contrary perhaps we should keep it. (On the other hand, I would find the latter somewhat more intuitive, and it would be much less likely to mask an unintended panic during testing.) |
This option would probably be quite tricky to implement, but first there are a bunch of details that would have to be specified:
|
I don't really see why a deferred call to |
We should immediately end the defer that called
That I do not know. To my knowledge we haven't specified what the stack looks like during a |
The doc for And if |
@bcmills and I spent a little while thinking and talking through this today. To me, if a deferred handler calls os.Exit in a panic, clearly the process exits and basically cancels the panic (there is no panic dump etc). So if a deferred handler calls runtime.Goexit in a panic, it seems OK to me that the goroutine exits "cleanly" rather than preserving the panic. That is, Goexit cancels a panic. On the other hand it's clear that panic/recover should not cancel Goexit, which was #35377 and is fixed. Based on this logic and trying some test cases, @bcmills and I believe this issue is working as intended and can be closed. |
I double-checked the behavior in a couple of Playground programs. https://go.dev/play/p/Adxb5z9XBvO looks reasonable to me: the https://go.dev/play/p/vmSAgH-DZgF looks wrong, but in the opposite direction from the title of this issue. The |
So the following functions are equivalent from behavior view? func foo() {
defer runtime.Goexit()
panic(1)
}
func bar() {
defer func() {recover()}()
panic(1)
}
func que() {
defer func() {
func() {
runtime.Goexit()
}()
}()
panic(1)
} |
If this is the final decision. I recommend to implement Goexit as harmless panic, to simplify the implementation. If the final uncaught panic is a Goexit, then program will not crash (maybe this is just the current implementation). |
@go101,
|
Yes, Goexit is unrecoverable painc. I mean those 3 functions are equivalent if they are used as goroutine start functions. |
Maybe, the spec also needs to update to be accurate. |
I just realized things are not so simple. Goexit sometimes behaves like panic, sometimes not. The final decision really twists the explanations for panic/recover mechanism to some degree. |
In go 1.13, but probably any version of go, a runtime.Goexit call can cancel a panic (example from @go101):
When you run this program, instead of getting a panic that terminates the program, you get a normal termination with no error. And generally, when a goroutine is panicking, a call to runtime.Goexit will just end the goroutine, but will cancel the panic, so the whole program may continue running.
This is not a big deal, since it has been like this for a long time and people are unlikely to run into it, but seems unexpected/incorrect.
One solution would be just to say that runtime.Goexit() is a no-op if we are in the middle of a panicking sequence. The slight downside to such a solution is that turning runtime.Goexit() to a no-op might be surprising and violate some programmer assumptions (especially if the runtime.Goexit call is buried deep within some other function/module), maybe leading to a second panic.
The text was updated successfully, but these errors were encountered: