Orderly exit

159 views
Skip to first unread message

Kevin Chadwick

unread,
Feb 23, 2021, 7:10:55 AM2/23/21
to golan...@googlegroups.com
I only instigate panic manually for one thing. Perhaps that will change, but I doubt it.

If I want to send out or write a log to disk then I will call panic rather than os.exit, upon a log.fatal scenario. Think buffered go routine logging. Saving the coder from having to think about it, once initialised.

Which produces some ugly output and likely extra processing.

Is it possible to call panic in a way that does not kill the process like os.Exit, but without log pollution?

I am solely thinking of manually instigated panics, so a noop panic called something like terminate?

Or is this bad practice, even when a program is in good operational order when instigated, as the OS is better at cleanup?

Axel Wagner

unread,
Feb 23, 2021, 7:50:35 AM2/23/21
to Kevin Chadwick, golang-nuts
On Tue, Feb 23, 2021 at 1:10 PM Kevin Chadwick <m8il...@gmail.com> wrote:
Is it possible to call panic in a way that does not kill the process like os.Exit, but without log pollution?  
 
I am solely thinking of manually instigated panics, so a noop panic called something like terminate?

You can `recover`. It's possible to use a private sentinel value to detect if a panic was caused by a known code-path or not and re-panic if not. For example, I sometimes use this pattern in parsers. It does have some downsides though - for example, if you do have to re-panic, you lose some context about where the bug happened.

There is also runtime.Goexit, which aborts a running goroutine, calling deferred handlers, but doesn't exit the program and doesn't log anything (and can't be recovered). It's used by `t.Fatal` and friends.
However, one thing to keep in mind is that this *might* cause problems if code isn't prepared for it. For example, it's natural to assume that a function either panics or runs to completion. And it might assume that it's fine to leave corrupted state because a panic should crash the program - or it might use `recover` to check if a panic occurred and conclude that none did when it gets `nil`. Technically, such code is wrong - it makes wrong assumptions about Go, like forgetting that panics exist, that Goexit exists or that panic(nil) is possible.

But buggy or not - they are natural assumptions to make and such code does exist and you might trigger subtle bugs by doing anything of the above. So in general, I would prefer orderly control flow, unless you can make reasonable assumptions about the code you are skipping over. For example, it's probably fine to trigger a bug like that in test code, because at worst, it will make the test fail (correctly detecting a bug) or the process will exit when the test is finished, cleaning up things. For example, I'm fine using the sentinel-panic pattern in parsers, because I control the code it's calling into and can make sure it only modifies state in a way compatible with the pattern.

For something like a logging framework, I would strongly prefer orderly control flow, crashing panics or no error checking. The code it's used in is largely unknown. And either logging is considered critical, in which case it needs to be checked or should crash if it fails, or it's not considered critical, in which case there's nothing to be done about an error and you might as well ignore it.


Or is this bad practice, even when a program is in good operational order when instigated, as the OS is better at cleanup?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/3A8FA632-4991-4245-ABB3-8F4CE1164703%40gmail.com.

Axel Wagner

unread,
Feb 23, 2021, 7:55:45 AM2/23/21
to Kevin Chadwick, golang-nuts
(PS: I've only learned about runtime.Goexit after I came up with the sentinel-panic pattern. I've been thinking for a while, that it is probably a better choice, for various reasons. And after testing it out, I do think it's strictly superior. So you should probably disregard the sentinel-panic idea, runtime.Goexit seems strictly superior) 

Kevin Chadwick

unread,
Feb 23, 2021, 8:30:49 AM2/23/21
to golan...@googlegroups.com
> So you should probably disregard the sentinel-panic idea,
> runtime.Goexit seems strictly superior)

Thank you. I shall look into those.

WRT Goexit. I was hoping a defer in main would run also. Thinking about it. I shall have to ponder about the relationship of panic and process groups too and whether a dedicated service like syslog is better. I may as well use syslog in that case but I had cross platform logging code that I figured, may be more flexible.

roger peppe

unread,
Feb 24, 2021, 4:54:33 AM2/24/21
to Kevin Chadwick, golang-nuts
Personally, I'd advise against using panic or log.Fatal in this kind of context - I'd just bite the bullet and return errors instead.
This makes it easy to move code between contexts if you need to without worrying about non-local control flow.

For unexpected panics, you can still use recover to flush your log buffers, assuming the panic happens in code that's been called by your code.

  cheers,
   rog. 

Kevin Chadwick

unread,
Feb 24, 2021, 1:15:13 PM2/24/21
to golang-nuts
On 2/24/21 9:53 AM, roger peppe wrote:
> On Tue, 23 Feb 2021 at 12:10, Kevin Chadwick <m8il...@gmail.com
> <mailto:m8il...@gmail.com>> wrote:
>
> I only instigate panic manually for one thing. Perhaps that will change, but
> I doubt it.
>
> If I want to send out or write a log to disk then I will call panic rather
> than os.exit, upon a log.fatal scenario. Think buffered go routine logging.
> Saving the coder from having to think about it, once initialised.
>
> Which produces some ugly output and likely extra processing.
>
> Is it possible to call panic in a way that does not kill the process like
> os.Exit, but without log pollution?
>
> I am solely thinking of manually instigated panics, so a noop panic called
> something like terminate?
>
> Or is this bad practice, even when a program is in good operational order
> when instigated, as the OS is better at cleanup?
>
>
> Personally, I'd advise against using panic or log.Fatal in this kind of context
> - I'd just bite the bullet and return errors instead.
> This makes it easy to move code between contexts if you need to without worrying
> about non-local control flow.
>

Yes, I avoid log.Fatal, wherever possible.

However, if I am for example running a drop privileges function and it fails
then I want an immediate exit. To avoid any potential of fragility.

Actually it seems that the panic never gets logged anyway and as the master
process is unlikely to fatal then a panic is unlikely to ever be seen. Perhaps
not ideal, but it works.

> For unexpected panics, you can still use recover to flush your log buffers,
> assuming the panic happens in code that's been called by your code.

I think I would rather os.Exit ASAP, in the case of an unexpected panic.

Robert Engels

unread,
Feb 24, 2021, 3:01:14 PM2/24/21
to Kevin Chadwick, golang-nuts
Depending on other infrastructure that can easily lead to easy DoS attacks.

> On Feb 24, 2021, at 12:15 PM, Kevin Chadwick <m8il...@gmail.com> wrote:
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/84a0db02-c4ec-15cf-cdd9-8543c1f9aa61%40gmail.com.

Kevin Chadwick

unread,
Feb 24, 2021, 5:04:42 PM2/24/21
to golan...@googlegroups.com
On February 24, 2021 8:00:36 PM UTC, Robert Engels <ren...@ix.netcom.com> wrote:
>Depending on other infrastructure that can easily lead to easy DoS
>attacks.

Utter nonsense, more likely the opposite, if any difference at all.

robert engels

unread,
Feb 24, 2021, 6:17:21 PM2/24/21
to Kevin Chadwick, golan...@googlegroups.com
I’m sorry but that is not correct. If you have a “server process” that handles requests for 1000’s of clients - terminating the process due to an exception/panic easily leads to a DoS attack. The bad actor only needs to send similar requests infrequently to affect thousands of users - especially with round-robin servicing - you can take down 1000’s of servers with 1:1 requests.
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/82940662-0589-4C68-AE4A-72AB0DBC36D3%40gmail.com.

Kevin Chadwick

unread,
Feb 24, 2021, 6:30:48 PM2/24/21
to golan...@googlegroups.com
On February 24, 2021 11:16:46 PM UTC, robert engels <ren...@ix.netcom.com> wrote:
>I’m sorry but that is not correct. If you have a “server process” that
>handles requests for 1000’s of clients - terminating the process due to
>an exception/panic easily leads to a DoS attack. The bad actor only
>needs to send similar requests infrequently to affect thousands of
>users - especially with round-robin servicing - you can take down
>1000’s of servers with 1:1 requests.
>

I figured after that I should have more politely said that. I am not sure what scenario you are thinking of but it doesn't apply to what I am doing.

Panics should not be triggerable by external influences, in any case.

robert engels

unread,
Feb 24, 2021, 6:33:31 PM2/24/21
to Kevin Chadwick, golan...@googlegroups.com
You can read the section ‘Apache Vulnerabilities’ and the difference in forking vs multi-threader Apache configuration and how that triggers a DoS. See https://www.feistyduck.com/library/apache-security/online/apachesc-CHP-5.html
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/7E95DC15-29E9-436C-9667-A9B7B67A312C%40ix.netcom.com.

robert engels

unread,
Feb 24, 2021, 6:37:32 PM2/24/21
to Kevin Chadwick, golan...@googlegroups.com
A simple slice OOB causes a panic - this is why many robust servers will catch & recover so a single OOB due to bug triggered by rare input/state doesn’t crash the server for 1000’s of users. It might still cause problems due to resource exhaustion, but properly designed exception/error handling should prevent/limit that.
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CDB3583B-6171-4025-B635-CC680FDDDF0D%40gmail.com.

Kevin Chadwick

unread,
Feb 24, 2021, 6:54:04 PM2/24/21
to golan...@googlegroups.com
On February 24, 2021 11:37:05 PM UTC, robert engels <ren...@ix.netcom.com> wrote:
>A simple slice OOB causes a panic - this is why many robust servers
>will catch & recover so a single OOB due to bug triggered by rare
>input/state doesn’t crash the server for 1000’s of users. It might
>still cause problems due to resource exhaustion, but properly designed
>exception/error handling should prevent/limit that.

I would rather fail safe than cater for a situation that shouldn't happen. Recovery is a less sane environment and there are better ways to build in redundancy.

Wrt forking. I was talking about dropping privileges, once at daemon startup.
Reply all
Reply to author
Forward
0 new messages