]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/pprof: return errors from writing profiles
authorSean Liao <sean@liao.dev>
Sun, 11 May 2025 20:55:57 +0000 (21:55 +0100)
committerSean Liao <sean@liao.dev>
Tue, 13 May 2025 17:01:48 +0000 (10:01 -0700)
Fixes #73107

Change-Id: I41f3e1bd1fdaca2f0e94151b2320bd569e258a51
Reviewed-on: https://go-review.googlesource.com/c/go/+/671576
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/runtime/pprof/pprof.go
src/runtime/pprof/proto.go
src/runtime/pprof/proto_test.go
src/runtime/pprof/protomem.go

index d295991ef7819358bc0559a71258863e7e90cac6..55563009b3a2c16a2a028032bbe017254905985e 100644 (file)
@@ -446,8 +446,7 @@ func printCountCycleProfile(w io.Writer, countName, cycleName string, records []
                locs = b.appendLocsForStack(locs[:0], expandedStack[:n])
                b.pbSample(values, locs, nil)
        }
-       b.build()
-       return nil
+       return b.build()
 }
 
 // printCountProfile prints a countProfile at the specified debug level.
@@ -517,8 +516,7 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
                }
                b.pbSample(values, locs, labels)
        }
-       b.build()
-       return nil
+       return b.build()
 }
 
 // keysByCount sorts keys with higher counts first, breaking ties by key string order.
index a664fdc6ed03e7ab0fbf30e3b2fa8355d39b2170..28ceb81542110a7795f26b009202140fe874ab4f 100644 (file)
@@ -345,7 +345,7 @@ func (b *profileBuilder) addCPUData(data []uint64, tags []unsafe.Pointer) error
 }
 
 // build completes and returns the constructed profile.
-func (b *profileBuilder) build() {
+func (b *profileBuilder) build() error {
        b.end = time.Now()
 
        b.pb.int64Opt(tagProfile_TimeNanos, b.start.UnixNano())
@@ -387,8 +387,11 @@ func (b *profileBuilder) build() {
        // TODO: Anything for tagProfile_KeepFrames?
 
        b.pb.strings(tagProfile_StringTable, b.strings)
-       b.zw.Write(b.pb.data)
-       b.zw.Close()
+       _, err := b.zw.Write(b.pb.data)
+       if err != nil {
+               return err
+       }
+       return b.zw.Close()
 }
 
 // appendLocsForStack appends the location IDs for the given stack trace to the given
index a4ae95d4c4d95c1fcabfe4f6266fb1f32496b984..b22d6e2b0366c383931a2ec00b20f6777cd477f8 100644 (file)
@@ -7,6 +7,7 @@ package pprof
 import (
        "bytes"
        "encoding/json"
+       "errors"
        "fmt"
        "internal/abi"
        "internal/profile"
@@ -33,7 +34,9 @@ func translateCPUProfile(data []uint64, count int) (*profile.Profile, error) {
        if err := b.addCPUData(data, tags); err != nil {
                return nil, err
        }
-       b.build()
+       if err := b.build(); err != nil {
+               return nil, err
+       }
        return profile.Parse(&buf)
 }
 
@@ -473,3 +476,16 @@ func TestEmptyStack(t *testing.T) {
                t.Fatalf("translating profile: %v", err)
        }
 }
+
+var errWrite = errors.New("error from writer")
+
+type errWriter struct{}
+
+func (errWriter) Write(p []byte) (int, error) { return 0, errWrite }
+
+func TestWriteToErr(t *testing.T) {
+       err := Lookup("heap").WriteTo(&errWriter{}, 0)
+       if !errors.Is(err, errWrite) {
+               t.Fatalf("want error from writer, got: %v", err)
+       }
+}
index 72aad82b3005343572c8be15b291720aefa904f4..e0d3746e3643707fa2617b1b9331ecd561771a48 100644 (file)
@@ -63,8 +63,7 @@ func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64,
                        }
                })
        }
-       b.build()
-       return nil
+       return b.build()
 }
 
 // scaleHeapSample adjusts the data from a heap Sample to