github.com/haraldrudell/parl@v0.4.176/panic-to-err.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import "github.com/haraldrudell/parl/perrors" 9 10 const ( 11 panicToErrAnnotation = "recover from panic: message:" 12 ) 13 14 // PanicToErr recovers active panic, aggregating errors in errp 15 // - PanicToErr does not provide enclosing function. For that, 16 // use RecoverErr: “recover from panic in pack.Func…” 17 // - errp cannot be nil 18 // - if isPanic is non-nil and active panic, it is set to true 19 // 20 // sample error message, including message in the panic value and the code line 21 // causing the panic: 22 // 23 // recover from panic: message: “runtime error: invalid memory address or nil pointer dereference” at parl.panicFunction()-panic-to-err_test.go:96 24 // 25 // Usage: 26 // 27 // func someFunc() (isPanic bool, err error) { 28 // defer parl.PanicToErr(&err, &isPanic) 29 // 30 // func someGoroutine(g parl.Go) { 31 // var err error 32 // defer g.Register().Done(&err) 33 // defer parl.PanicToErr(&err) 34 func PanicToErr(errp *error, isPanic ...*bool) { 35 if errp == nil { 36 panic(NilError("errp")) 37 } 38 39 // if no panic, noop 40 // - recover invocation must be directly in the PanicToErr function 41 var panicValue = recover() 42 if panicValue == nil { 43 return // no panic active return 44 } 45 46 // set isPanic if non-nil 47 if len(isPanic) > 0 { 48 if isPanicp := isPanic[0]; isPanicp != nil { 49 *isPanicp = true 50 } 51 } 52 53 // append panic to *errp 54 // - for panic detector to work there needs to be at least one stack frame after runtime’s 55 // panic handler 56 // - because PanicToErr is invoked directly by the runtime, possibly runtime.gopanic, 57 // the PanicToErr stack frame must be included. 58 // Therefore, 0 argument to processRecover 59 *errp = perrors.AppendError(*errp, processRecoverValue(panicToErrAnnotation, panicValue, 0)) 60 }