mirror of
https://github.com/wader/fq.git
synced 2024-11-22 07:16:49 +03:00
decode,fuzz,dev: Move recoverable error check to recoverfn.Run
This preserves the callstack on non-recoverable panics so that using a debugger and fuzzing is much easier. Add vscode debug config. Remove fuzz stacktrace log workaround.
This commit is contained in:
parent
664bc3b1b7
commit
c5f6809b02
21
.vscode/launch.json
vendored
Normal file
21
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug fq",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"showLog": true,
|
||||
"program": ".",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {},
|
||||
"args": [
|
||||
"-d",
|
||||
"mp4",
|
||||
".",
|
||||
"file"
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -61,6 +61,7 @@
|
||||
"gojqex",
|
||||
"golangci",
|
||||
"gopacket",
|
||||
"gopanic",
|
||||
"GOPATH",
|
||||
"gosec",
|
||||
"gosimple",
|
||||
@ -154,6 +155,8 @@
|
||||
"tfhd",
|
||||
"tfra",
|
||||
"tmpl",
|
||||
"to_xml",
|
||||
"to_xmlentities",
|
||||
"toactual",
|
||||
"toarray",
|
||||
"toboolean",
|
||||
@ -167,8 +170,6 @@
|
||||
"torepr",
|
||||
"tosym",
|
||||
"tovalue",
|
||||
"to_xml",
|
||||
"to_xmlentities",
|
||||
"traf",
|
||||
"trak",
|
||||
"trex",
|
||||
|
2
Makefile
2
Makefile
@ -92,7 +92,7 @@ update-gomod: always
|
||||
# fq -n '"..." | from_base64 | ...'
|
||||
fuzz: always
|
||||
# in other terminal: tail -f /tmp/repanic
|
||||
FUZZTEST=1 REPANIC_LOG=/tmp/repanic go test -v -run Fuzz -fuzz=Fuzz ./format/
|
||||
FUZZTEST=1 go test -v -run Fuzz -fuzz=Fuzz ./format/
|
||||
|
||||
# usage: make release VERSION=0.0.1
|
||||
# tag forked dependeces for history and to make then stay around
|
||||
|
@ -1,9 +1,6 @@
|
||||
package recoverfn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
@ -15,8 +12,13 @@ type Raw struct {
|
||||
PCs []uintptr
|
||||
}
|
||||
|
||||
// Run runs fn and return Raw{}, true on no-panic
|
||||
// on panic it recovers and return a raw stacktrace and panic value to inspect
|
||||
type RecoverableErrorer interface {
|
||||
IsRecoverableError() bool
|
||||
}
|
||||
|
||||
// Run runs fn and return Raw{}, true for no panic
|
||||
// If panic is recoverable raw stacktrace and panic value is returned
|
||||
// If panic is not recoverable we just panic again
|
||||
func Run(fn func()) (Raw, bool) {
|
||||
// TODO: once?
|
||||
var recoverPC [1]uintptr
|
||||
@ -24,10 +26,14 @@ func Run(fn func()) (Raw, bool) {
|
||||
|
||||
pc, v := func() (pcs []uintptr, v any) {
|
||||
defer func() {
|
||||
if recoverErr := recover(); recoverErr != nil {
|
||||
pcs = make([]uintptr, stackSizeLimit)
|
||||
pcs = pcs[0:runtime.Callers(0, pcs)]
|
||||
v = recoverErr
|
||||
if recoverV := recover(); recoverV != nil {
|
||||
if re, ok := recoverV.(RecoverableErrorer); ok && re.IsRecoverableError() {
|
||||
pcs = make([]uintptr, stackSizeLimit)
|
||||
pcs = pcs[0:runtime.Callers(0, pcs)]
|
||||
v = recoverV
|
||||
return
|
||||
}
|
||||
panic(recoverV)
|
||||
}
|
||||
}()
|
||||
|
||||
@ -81,21 +87,3 @@ func (r Raw) Frames() []runtime.Frame {
|
||||
// 1 to skip Recover defer recover() function
|
||||
return r.frames(3, 1, r.RecoverPC)
|
||||
}
|
||||
|
||||
func (r Raw) RePanic() {
|
||||
var o io.Writer
|
||||
o = os.Stderr
|
||||
if p := os.Getenv("REPANIC_LOG"); p != "" {
|
||||
if f, err := os.Create(p); err == nil {
|
||||
o = f
|
||||
defer f.Close()
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(o, "repanic: %v\n", r.RecoverV)
|
||||
for _, f := range r.frames(0, 0, 0) {
|
||||
fmt.Fprintf(o, "%s\n", f.Function)
|
||||
fmt.Fprintf(o, "\t%s:%d\n", f.File, f.Line)
|
||||
}
|
||||
panic(r.RecoverV)
|
||||
}
|
||||
|
@ -8,13 +8,17 @@ import (
|
||||
)
|
||||
|
||||
func test1() {
|
||||
panic("hello")
|
||||
panic(testError(true))
|
||||
}
|
||||
|
||||
func test2() {
|
||||
test1()
|
||||
}
|
||||
|
||||
type testError bool
|
||||
|
||||
func (t testError) IsRecoverableError() bool { return bool(t) }
|
||||
|
||||
func TestNormal(t *testing.T) {
|
||||
_, rOk := recoverfn.Run(func() {})
|
||||
expectedROK := true
|
||||
@ -31,9 +35,8 @@ func TestPanic(t *testing.T) {
|
||||
t.Errorf("expected v %v, got %v", expectedROK, rOk)
|
||||
}
|
||||
|
||||
expectedV := "hello"
|
||||
if !reflect.DeepEqual(expectedV, r.RecoverV) {
|
||||
t.Errorf("expected v %v, got %v", expectedV, r.RecoverV)
|
||||
if _, ok := r.RecoverV.(testError); !ok {
|
||||
t.Errorf("expected v %v, got %v", testError(true), r.RecoverV)
|
||||
}
|
||||
|
||||
frames := r.Frames()
|
||||
|
@ -106,27 +106,29 @@ func decode(ctx context.Context, br bitio.ReaderAtSeeker, group Group, opts Opti
|
||||
}
|
||||
|
||||
if !rOk {
|
||||
if re, ok := r.RecoverV.(RecoverableErrorer); ok && re.IsRecoverableError() {
|
||||
panicErr, _ := re.(error)
|
||||
formatErr := FormatError{
|
||||
Err: panicErr,
|
||||
Format: f,
|
||||
Stacktrace: r,
|
||||
}
|
||||
formatsErr.Errs = append(formatsErr.Errs, formatErr)
|
||||
|
||||
switch vv := d.Value.V.(type) {
|
||||
case *Compound:
|
||||
// TODO: hack, changes V
|
||||
d.Value.V = vv
|
||||
d.Value.Err = formatErr
|
||||
}
|
||||
|
||||
if len(group) != 1 {
|
||||
continue
|
||||
}
|
||||
var panicErr error
|
||||
if err, ok := r.RecoverV.(error); ok {
|
||||
panicErr = err
|
||||
} else {
|
||||
r.RePanic()
|
||||
panicErr = fmt.Errorf("recoverable non-panic error :%v", r.RecoverV)
|
||||
}
|
||||
|
||||
formatErr := FormatError{
|
||||
Err: panicErr,
|
||||
Format: f,
|
||||
Stacktrace: r,
|
||||
}
|
||||
formatsErr.Errs = append(formatsErr.Errs, formatErr)
|
||||
|
||||
switch vv := d.Value.V.(type) {
|
||||
case *Compound:
|
||||
// TODO: hack, changes V
|
||||
d.Value.V = vv
|
||||
d.Value.Err = formatErr
|
||||
}
|
||||
|
||||
if len(group) != 1 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user