go: os: Exit does not respect deferred functions making any cleanup code useless

What version of Go are you using (go version)?

$ go version
go version go1.14.1 windows/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
set GO111MODULE=auto
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\anonymous\AppData\Local\go-build
set GOENV=C:\Users\anonymous\AppData\Roaming\go\env
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\anonymous\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=c:\go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=c:\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=C:\Users\anonymous\Desktop\an\go.mod
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\anon~1\AppData\Local\Temp\go-build078526234=/tmp/go-build -gno-record-gcc-switches

What did you do?

I called os.Exit(1) on SIGINT https://play.golang.org/p/_Py0WToAf8v (Local testing is better, playground does not like sleeps and have no way to cause a SIGINT).

What did you expect to see?

Golang runs all deferred cleanup routines. This would allow every go routine to register it’s own cleanup function if you think separation of concerns is a thing.

What did you see instead?

No Cleanup function is called at all, but that is important if you’re writing to files in other goroutines. Panic have a similiar issue.

See also: #4101

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 17 (3 by maintainers)

Most upvoted comments

@ccbrown I already explained the use case. And I think contexts are not applicable because you can’t interrupt sleeping goroutines. What about blocking file operations for example.

If you look at my example, you will see that Cancelation won’t work here as the main routine is not able to cancel the goroutine (the process exit is triggered by the goroutine itself). I’m not sure how you get separation of concerns with contexts, because my idea is, that everyn goroutine should be responsible for the cleanup it must do (btw this makes code a lot more understandable und reusable, because you haven’t any hidden dependencies with other code pieces that have to do cleanup for goroutines in the case of an early exit). And as far as I can remember the defer call was advertised for cleanup tasks. Which, as we can see is not a reliable way if the application panics or if the process is killed. See my example on playground.

And I think it’s a common task to do some cleanup if the user interrupts the process with SIGINT before exiting. The other way arround I’m question myself why we have os.Exit if it’s not applicable to reliable close a process. It does not respect defers. Some of go’s core features.

@ccbrown most of the other languages have other methods ensuring that cleanup code can run on a call to exit. This doesn’t necessary have to happen inside a destructor (or a defer call) but it would make things much less annoying. An example in C++ is atexit. I don’t know a similiar golang mechanism. And saying, no language did this that way is not a really good reason for not doing it. Golang does many things other languages do not do. And as far as I can remember a simliar policy applies for stuff people want golang to have.