Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are all runtime errors recoverable in Go?

Tags:

go

I think an equivalent question is - do all runtime errors, which may be fatal, panic? Because anything that panics should be recoverable. I'm not talking about recovering from things like os.Exit(), or log.Fatal(), or bugs in the Go runtime, or someone tripping over the power cord, but from other runtime errors which will lead to the program crashing.

Here's an example of a runtime error that can be caught via panic/recover:

package main

import (
    "fmt"
)

func errorHandler() {
    r := recover()
    err := r.(error)
    if err == nil {
        return
    }
    fmt.Println(err.Error())
}

func foo() {
    defer errorHandler()
    smallSlice := []int{1, 0, 1}
    smallSlice[10] = 1
}

func main() {
    foo()
    fmt.Println("recovery, end of main")
}

output:

runtime error: index out of range
recovery, end of main

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

like image 616
chrishiestand Avatar asked Aug 13 '19 23:08

chrishiestand


People also ask

What happens if a Goroutine panic?

A panic stops the normal execution of a goroutine: When a program panics, it immediately starts to unwind the call stack. This continues until the program crashes and prints a stack trace, or until the built-in recover function is called.

What is panic and recover in Golang?

Golang panic We use the panic statement to immediately end the execution of the program. If our program reaches a point where it cannot be recovered due to some major errors, it's best to use panic. The lines of code after the panic statement are not executed. For example, package main import "fmt" func main() { fmt.

What is panic error in Golang?

What is panic() in Golang? Samia Ishaque. The panic() function in Go Language is similar to exceptions raised at runtime when an error is encountered. panic() is either raised by the program itself when an unexpected error occurs or the programmer throws the exception on purpose for handling particular errors.

What is recovery in Golang?

Overview. The recover() function in Go Language is used to recover from a goroutine that is in panic, meaning it helps recover from an error that has been raised. The program takes control through recover rather than letting the code crash. recover() is an inbuilt function in Go Language.


Video Answer


2 Answers

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.

like image 104
icza Avatar answered Oct 13 '22 23:10

icza


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() {
    // ...
}
like image 41
peterSO Avatar answered Oct 14 '22 00:10

peterSO