]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/pprof: handle empty stack traces in Profile.Add
authorJosh Bleecher Snyder <josharian@gmail.com>
Sat, 11 Feb 2017 22:44:16 +0000 (14:44 -0800)
committerJosh Bleecher Snyder <josharian@gmail.com>
Mon, 27 Feb 2017 17:11:07 +0000 (17:11 +0000)
If the caller passes a large number to Profile.Add,
the list of pcs is empty, which results in junk
(a nil pc) being recorded. Check for that explicitly,
and replace such stack traces with a lostProfileEvent.

Fixes #18836.

Change-Id: I99c96aa67dd5525cd239ea96452e6e8fcb25ce02
Reviewed-on: https://go-review.googlesource.com/36891
Reviewed-by: Russ Cox <rsc@golang.org>
src/runtime/pprof/pprof.go
src/runtime/pprof/pprof_test.go

index e44921cf83781350ad7b0124471b51be66b11db9..4d1068d66523ca7803a0707cf02669fe7d5506cb 100644 (file)
@@ -267,13 +267,18 @@ func (p *Profile) Add(value interface{}, skip int) {
 
        stk := make([]uintptr, 32)
        n := runtime.Callers(skip+1, stk[:])
+       stk = stk[:n]
+       if len(stk) == 0 {
+               // The value for skip is too large, and there's no stack trace to record.
+               stk = []uintptr{funcPC(lostProfileEvent)}
+       }
 
        p.mu.Lock()
        defer p.mu.Unlock()
        if p.m[value] != nil {
                panic("pprof: Profile.Add of duplicate value")
        }
-       p.m[value] = stk[:n]
+       p.m[value] = stk
 }
 
 // Remove removes the execution stack associated with value from the profile.
index 044329246b65735ab07889bfe61dea94d433204d..2b82e68be754f3d71e676d22bb15bd6230064671 100644 (file)
@@ -635,3 +635,22 @@ func containsCounts(prof *profile.Profile, counts []int64) bool {
        }
        return true
 }
+
+// Issue 18836.
+func TestEmptyCallStack(t *testing.T) {
+       t.Parallel()
+       var buf bytes.Buffer
+       p := NewProfile("test18836")
+       p.Add("foo", 47674)
+       p.WriteTo(&buf, 1)
+       p.Remove("foo")
+       got := buf.String()
+       prefix := "test18836 profile: total 1\n"
+       if !strings.HasPrefix(got, prefix) {
+               t.Fatalf("got:\n\t%q\nwant prefix:\n\t%q\n", got, prefix)
+       }
+       lostevent := "lostProfileEvent"
+       if !strings.Contains(got, lostevent) {
+               t.Fatalf("got:\n\t%q\ndoes not contain:\n\t%q\n", got, lostevent)
+       }
+}