Are all runtime errors recoverable in Go?

Are there any examples where runtime errors will just crash the program without a recoverable panic?


For example, Go Out-Of-Memory (OOM) errors are not recoverable.


src/runtime/panic.go:

// fatalpanic implements an unrecoverable panic. It is like fatalthrow, except
// that if msgs != nil, fatalpanic also prints panic messages and decrements
// runningPanicDefers once main is blocked from exiting.
func fatalpanic(msgs *_panic) {
    // ...
}

// fatalthrow implements an unrecoverable runtime throw. It freezes the
// system, prints stack traces starting from its caller, and terminates the
// process.
func fatalthrow() {
    // ...
}

First change your errorHandler() because if there are no panics, r will be nil and thus the type assertion would fail:

func errorHandler() {
    if r := recover(); r != nil {
        fmt.Println(r)
    }
}

And now here are some examples with code to produce unrecoverable runtime errors:

1. Out of memory:

func foo() {
    defer errorHandler()
    _ = make([]int64, 1<<40) // You have to change the size on 32-bit systems
}

2. Concurrent map writes and reads

For details see How to recover from concurrent map writes?, for example see Can marshalling a map[string]string to json return an error?

func foo() {
    defer errorHandler()
    m := map[string]int{}

    go func() {
        for {
            m["x"] = 1
        }
    }()
    for {
        _ = m["x"]
    }
}

3. Stack memory exhaustion

For details, see Does Go have an "infinite call stack" equivalent?

func foo() {
    defer errorHandler()

    var f func(a [1000]int64)
    f = func(a [1000]int64) {
        f(a)
    }
    f([1000]int64{})
}

4. Attempting to launch a nil function as a goroutine

func foo() {
    defer errorHandler()
    var f func()
    go f()
}

5. All goroutines are asleep - deadlock

Title says it all. Here's a simple code to block the current goroutine, but if you have launched other goroutines, you obviously won't experience the crash. See other examples here: Go project's main goroutine sleep forever?

func foo() {
    defer errorHandler()
    select {}
}

6. Thread limit exhaustion

If your goroutines get blocked by IO operations, new threads may be started to execute your other goroutines. There is obviously a limit to the max thread count, if it is reached, your app will crash.

Tags:

Go