Go

Do deferred functions run on os.Exit, log.Fatal, runtime.Goexit and panic?

Question 19MediumGo 1.22 to 1.25
  • panic: yes. Deferred calls run while the stack unwinds, and that is where recover can happen.
  • runtime.Goexit: yes. It ends the current goroutine and runs its defers. t.FailNow() in tests uses it. It can't be recovered, and calling it from main causes a deadlock crash once all other goroutines finish.
  • os.Exit: no. The process exits immediately. Defers are skipped, and buffers such as bufio.Writer are not flushed.
  • log.Fatal / log.Fatalf: no. They call os.Exit(1).
func main() {
	defer fmt.Println("cleanup") // never printed
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

// Idiomatic: do the work in run(), so its defers run and main is the only place that exits.
func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run() error {
	f, err := os.Create("out.txt")
	if err != nil {
		return err
	}
	defer f.Close() // always runs
	// ...
	return nil
}

What the interviewer wants to hear: the run() error pattern, and awareness that log.Fatal in library code is bad practice.

More on Language Fundamentals & Types

All 39 Language Fundamentals & Types questions