Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions internal/stack/stacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,17 @@ func (s Stack) String() string {
}

func getStacks(all bool) []Stack {
trace := getStackBuffer(all)
return parseStacks(getStackBuffer(all))
}

// parseStacks parses a stack trace produced by runtime.Stack.
//
// It panics if the trace is malformed, since well-formed stack traces
// produced by the runtime should never fail to parse.
// If they do, it's a bug in this package, and panicking lets us fix it.
func parseStacks(trace []byte) []Stack {
stacks, err := newStackParser(bytes.NewReader(trace)).Parse()
if err != nil {
// Well-formed stack traces should never fail to parse.
// If they do, it's a bug in this package.
// Panic so we can fix it.
panic(fmt.Sprintf("Failed to parse stack trace: %v\n%s", err, trace))
}
return stacks
Expand Down
20 changes: 20 additions & 0 deletions internal/stack/stacks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,26 @@ func TestAllLargeStack(t *testing.T) {
close(done)
}

func TestParseStacksPanicsOnMalformedTrace(t *testing.T) {
// getStacks relies on runtime.Stack always producing well-formed
// traces, and panics if parsing ever fails. Exercise that path
// directly with a malformed trace since the runtime won't produce one.
malformed := []byte("goroutine no-number [running]:\n")

recovered := func() (recovered any) {
defer func() { recovered = recover() }()
parseStacks(malformed)
return
}()

msg, ok := recovered.(string)
require.True(t, ok, "panic value should be a string, got %T", recovered)
assert.Contains(t, msg, "Failed to parse stack trace")
assert.Contains(t, msg, "bad goroutine ID")
// The offending trace should be included to aid debugging.
assert.Contains(t, msg, string(malformed))
}

func TestParseFuncName(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading