]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/go: add check for unknown godebug setting
authorRuss Cox <rsc@golang.org>
Tue, 14 Mar 2023 18:25:56 +0000 (14:25 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 18 Apr 2023 13:19:19 +0000 (13:19 +0000)
A //go:debug line mentioning an unknown or retired setting
should be diagnosed as making the program invalid. Do that.
We agreed on this in the proposal but I forgot to implement it.

Change-Id: Ie69072a1682d4eeb6866c02adbbb426f608567c4
Reviewed-on: https://go-review.googlesource.com/c/go/+/476280
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

21 files changed:
misc/cgo/testshared/shared_test.go
src/cmd/dist/buildtool.go
src/cmd/go/gotoolchain.go
src/cmd/go/internal/fsys/fsys.go
src/cmd/go/internal/load/godebug.go
src/cmd/go/internal/modindex/read.go
src/cmd/go/testdata/script/godebug_unknown.txt [new file with mode: 0644]
src/go/build/deps_test.go
src/internal/cpu/cpu_test.go
src/internal/cpu/cpu_x86_test.go
src/internal/fuzz/fuzz.go
src/internal/godebug/godebug.go
src/internal/godebug/godebug_test.go
src/internal/godebugs/godebugs_test.go [new file with mode: 0644]
src/internal/godebugs/table.go [new file with mode: 0644]
src/internal/intern/intern.go
src/mime/multipart/formdata.go
src/os/exec/exec.go
src/runtime/metrics.go
src/runtime/metrics/description.go
src/runtime/metrics/doc.go

index e300e20e2008053b0cfc04aeff329e35252d9696..3a8fda05ed78e60c38a7fe76fe253c425a33c647 100644 (file)
@@ -219,7 +219,7 @@ func cloneGOROOTDeps(goroot string) error {
        for _, pkg := range pkgs {
                parentFound := false
                for _, prev := range pkgRoots {
-                       if strings.HasPrefix(pkg, prev) {
+                       if pkg == prev || strings.HasPrefix(pkg, prev+"/") {
                                // We will copy in the source for pkg when we copy in prev.
                                parentFound = true
                                break
index 09b8750dc8a473679a18edcd6b40eefdd60ebfbb..3a455b9677486190ffd7e255203533d1ea95cac5 100644 (file)
@@ -65,6 +65,7 @@ var bootstrapDirs = []string{
        "internal/coverage",
        "internal/buildcfg",
        "internal/goarch",
+       "internal/godebugs",
        "internal/goexperiment",
        "internal/goroot",
        "internal/goversion",
index a0512245f040f4e0f6e834455ad6e538859bcfb3..5b7468f21fd29198586dae665ac86859dee36de9 100644 (file)
@@ -187,7 +187,7 @@ func execGoToolchain(gotoolchain, dir, exe string) {
        // propagate signals and such, but there are no signals on Windows.
        // We also use the exec case when GODEBUG=gotoolchainexec=0,
        // to allow testing this code even when not on Windows.
-       if godebug.New("gotoolchainexec").Value() == "0" || runtime.GOOS == "windows" {
+       if godebug.New("#gotoolchainexec").Value() == "0" || runtime.GOOS == "windows" {
                cmd := exec.Command(exe, os.Args[1:]...)
                if runtime.GOOS == "windows" && strings.Contains(exe, "go1.999test") {
                        // See testdata/script/gotoolchain.txt.
index 57a8c2c352d4792c796000095f4b61f780846ad3..c371610a4d896af69e60adbae41cf772a2baa850 100644 (file)
@@ -48,9 +48,9 @@ var (
        traceFile *os.File
        traceMu   sync.Mutex
 
-       gofsystrace      = godebug.New("gofsystrace")
-       gofsystracelog   = godebug.New("gofsystracelog")
-       gofsystracestack = godebug.New("gofsystracestack")
+       gofsystrace      = godebug.New("#gofsystrace")
+       gofsystracelog   = godebug.New("#gofsystracelog")
+       gofsystracestack = godebug.New("#gofsystracestack")
 )
 
 func init() {
index f65c40d3e0ed021d0131425dda1b7ddb6d96f9aa..c79245e5cd92313571ad4e3513ab3e548690fce0 100644 (file)
@@ -9,6 +9,7 @@ import (
        "errors"
        "fmt"
        "go/build"
+       "internal/godebugs"
        "sort"
        "strconv"
        "strings"
@@ -43,7 +44,13 @@ func ParseGoDebug(text string) (key, value string, err error) {
        if strings.ContainsAny(v, ",") {
                return "", "", fmt.Errorf("value contains comma")
        }
-       return k, v, nil
+
+       for _, info := range godebugs.All {
+               if k == info.Name {
+                       return k, v, nil
+               }
+       }
+       return "", "", fmt.Errorf("unknown //go:debug setting %q", k)
 }
 
 // defaultGODEBUG returns the default GODEBUG setting for the main package p.
@@ -110,19 +117,10 @@ func godebugForGoVersion(v string) map[string]string {
        }
 
        def := make(map[string]string)
-       for _, d := range defaultGodebugs {
-               if (d.before != 0 && n < d.before) || (d.first != 0 && n >= d.first) {
-                       def[d.name] = d.value
+       for _, info := range godebugs.All {
+               if n < info.Changed {
+                       def[info.Name] = info.Old
                }
        }
        return def
 }
-
-var defaultGodebugs = []struct {
-       before int // applies to Go versions up until this one (21 for Go 1.21)
-       first  int // applies to Go versions starting at this one (21 for Go 1.21)
-       name   string
-       value  string
-}{
-       {before: 21, name: "panicnil", value: "1"},
-}
index 352b87ed629f1a40d7c0d909cf5965eb53cbcd2a..1fa250ad47c5d9442c74c228feefdacbeebf70e2 100644 (file)
@@ -37,7 +37,7 @@ import (
 // It will be removed before the release.
 // TODO(matloob): Remove enabled once we have more confidence on the
 // module index.
-var enabled = godebug.New("goindex").Value() != "0"
+var enabled = godebug.New("#goindex").Value() != "0"
 
 // Module represents and encoded module index file. It is used to
 // do the equivalent of build.Import of packages in the module and answer other
diff --git a/src/cmd/go/testdata/script/godebug_unknown.txt b/src/cmd/go/testdata/script/godebug_unknown.txt
new file mode 100644 (file)
index 0000000..57dacbc
--- /dev/null
@@ -0,0 +1,9 @@
+! go build
+stderr 'p.go:1:1: invalid //go:debug: unknown //go:debug setting "x"'
+
+-- go.mod --
+module m
+-- p.go --
+//go:debug x=y
+package main
+func main() {}
index de80ed041f48b299c83a9303e9f76d5a33e9ef75..3238d96b9da42afd9bfe93d48d84bd2ada52fd85 100644 (file)
@@ -42,7 +42,7 @@ var depsRules = `
        < constraints, container/list, container/ring,
          internal/cfg, internal/coverage, internal/coverage/rtcov,
          internal/coverage/uleb128, internal/coverage/calloc,
-         internal/cpu, internal/goarch,
+         internal/cpu, internal/goarch, internal/godebugs,
          internal/goexperiment, internal/goos,
          internal/goversion, internal/nettrace, internal/platform,
          log/internal,
@@ -55,7 +55,7 @@ var depsRules = `
 
        # RUNTIME is the core runtime group of packages, all of them very light-weight.
        internal/abi, internal/cpu, internal/goarch,
-       internal/coverage/rtcov, internal/goexperiment,
+       internal/coverage/rtcov, internal/godebugs, internal/goexperiment,
        internal/goos, unsafe
        < internal/bytealg
        < internal/itoa
index 5aa277f960a2f4d51f07e37a24f4d786c9922a77..b8c74f2e9cb6e7e203dd42f0892b26046e3016c6 100644 (file)
@@ -48,7 +48,7 @@ func TestDisableAllCapabilities(t *testing.T) {
 func TestAllCapabilitiesDisabled(t *testing.T) {
        MustHaveDebugOptionsSupport(t)
 
-       if godebug.New("cpu.all").Value() != "off" {
+       if godebug.New("#cpu.all").Value() != "off" {
                t.Skipf("skipping test: GODEBUG=cpu.all=off not set")
        }
 
index d7be4308a2a34b641105320651ffc635c3951806..8564ccc79952f71d91b7ca29addd76ce9315a37f 100644 (file)
@@ -28,7 +28,7 @@ func TestDisableSSE3(t *testing.T) {
 func TestSSE3DebugOption(t *testing.T) {
        MustHaveDebugOptionsSupport(t)
 
-       if godebug.New("cpu.sse3").Value() != "off" {
+       if godebug.New("#cpu.sse3").Value() != "off" {
                t.Skipf("skipping test: GODEBUG=cpu.sse3=off not set")
        }
 
index 8e4351e011f9b16e64f7c8f559383bdc3c30dd4e..fb4e1d37055eeb6adb75a94dc24661f17fd2ccdd 100644 (file)
@@ -1090,7 +1090,7 @@ var zeroVals []any = []any{
        uint64(0),
 }
 
-var debugInfo = godebug.New("fuzzdebug").Value() == "1"
+var debugInfo = godebug.New("#fuzzdebug").Value() == "1"
 
 func shouldPrintDebugInfo() bool {
        return debugInfo
index 679e3df8d69bda9ad8e36df7d97c10bcc12747e1..cecbe7d585e4e697d368d7de03833d8933a61733 100644 (file)
@@ -30,6 +30,7 @@
 package godebug
 
 import (
+       "internal/godebugs"
        "sync"
        "sync/atomic"
        _ "unsafe" // go:linkname
@@ -46,21 +47,38 @@ type setting struct {
        value          atomic.Pointer[string]
        nonDefaultOnce sync.Once
        nonDefault     atomic.Uint64
+       info           *godebugs.Info
 }
 
 // New returns a new Setting for the $GODEBUG setting with the given name.
+//
+// GODEBUGs meant for use by end users must be listed in ../godebugs/table.go,
+// which is used for generating and checking various documentation.
+// If the name is not listed in that table, New will succeed but calling Value
+// on the returned Setting will panic.
+// To disable that panic for access to an undocumented setting,
+// prefix the name with a #, as in godebug.New("#gofsystrace").
+// The # is a signal to New but not part of the key used in $GODEBUG.
 func New(name string) *Setting {
        return &Setting{name: name}
 }
 
 // Name returns the name of the setting.
 func (s *Setting) Name() string {
+       if s.name != "" && s.name[0] == '#' {
+               return s.name[1:]
+       }
        return s.name
 }
 
+// Undocumented reports whether this is an undocumented setting.
+func (s *Setting) Undocumented() bool {
+       return s.name != "" && s.name[0] == '#'
+}
+
 // String returns a printable form for the setting: name=value.
 func (s *Setting) String() string {
-       return s.name + "=" + s.Value()
+       return s.Name() + "=" + s.Value()
 }
 
 // IncNonDefault increments the non-default behavior counter
@@ -69,20 +87,16 @@ func (s *Setting) String() string {
 // /godebug/non-default-behavior/<name>:events.
 //
 // Note that Value must be called at least once before IncNonDefault.
-//
-// Any GODEBUG setting that can call IncNonDefault must be listed
-// in three more places:
-//
-//   - the table in ../runtime/metrics.go (search for non-default-behavior)
-//   - the table in ../../runtime/metrics/description.go (search for non-default-behavior; run 'go generate' afterward)
-//   - the table in ../../cmd/go/internal/load/godebug.go (search for defaultGodebugs)
 func (s *Setting) IncNonDefault() {
        s.nonDefaultOnce.Do(s.register)
        s.nonDefault.Add(1)
 }
 
 func (s *Setting) register() {
-       registerMetric("/godebug/non-default-behavior/"+s.name+":events", s.nonDefault.Load)
+       if s.info == nil || s.info.Opaque {
+               panic("godebug: unexpected IncNonDefault of " + s.name)
+       }
+       registerMetric("/godebug/non-default-behavior/"+s.Name()+":events", s.nonDefault.Load)
 }
 
 // cache is a cache of all the GODEBUG settings,
@@ -111,7 +125,10 @@ var empty string
 // caching of Value's result.
 func (s *Setting) Value() string {
        s.once.Do(func() {
-               s.setting = lookup(s.name)
+               s.setting = lookup(s.Name())
+               if s.info == nil && !s.Undocumented() {
+                       panic("godebug: Value of name not listed in godebugs.All: " + s.name)
+               }
        })
        return *s.value.Load()
 }
@@ -122,6 +139,7 @@ func lookup(name string) *setting {
                return v.(*setting)
        }
        s := new(setting)
+       s.info = godebugs.Lookup(name)
        s.value.Store(&empty)
        if v, loaded := cache.LoadOrStore(name, s); loaded {
                // Lost race: someone else created it. Use theirs.
index 2f311106b18d02d1f30ea382e29ae8420bcadfdb..ad5ced355843ce3c0ed58c63d622759f404a8ef7 100644 (file)
@@ -11,13 +11,13 @@ import (
 )
 
 func TestGet(t *testing.T) {
-       foo := New("foo")
+       foo := New("#foo")
        tests := []struct {
                godebug string
                setting *Setting
                want    string
        }{
-               {"", New(""), ""},
+               {"", New("#"), ""},
                {"", foo, ""},
                {"foo=bar", foo, "bar"},
                {"foo=bar,after=x", foo, "bar"},
@@ -28,7 +28,7 @@ func TestGet(t *testing.T) {
                {"foo=", foo, ""},
                {"foo", foo, ""},
                {",foo", foo, ""},
-               {"foo=bar,baz", New("loooooooong"), ""},
+               {"foo=bar,baz", New("#loooooooong"), ""},
        }
        for _, tt := range tests {
                t.Setenv("GODEBUG", tt.godebug)
diff --git a/src/internal/godebugs/godebugs_test.go b/src/internal/godebugs/godebugs_test.go
new file mode 100644 (file)
index 0000000..663268f
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package godebugs_test
+
+import (
+       "internal/godebugs"
+       "os"
+       "strings"
+       "testing"
+)
+
+func TestAll(t *testing.T) {
+       data, err := os.ReadFile("../../../doc/godebug.md")
+       if err != nil {
+               t.Fatal(err)
+       }
+       doc := string(data)
+
+       last := ""
+       for _, info := range godebugs.All {
+               if info.Name <= last {
+                       t.Errorf("All not sorted: %s then %s", last, info.Name)
+               }
+               last = info.Name
+
+               if info.Package == "" {
+                       t.Errorf("Name=%s missing Package", info.Name)
+               }
+               if info.Changed != 0 && info.Old == "" {
+                       t.Errorf("Name=%s has Changed, missing Old", info.Name)
+               }
+               if info.Old != "" && info.Changed == 0 {
+                       t.Errorf("Name=%s has Old, missing Changed", info.Name)
+               }
+               if !strings.Contains(doc, "`"+info.Name+"`") {
+                       t.Errorf("Name=%s not documented in doc/godebug.md", info.Name)
+               }
+       }
+}
diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go
new file mode 100644 (file)
index 0000000..6a78d74
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package godebugs provides a table of known GODEBUG settings,
+// for use by a variety of other packages, including internal/godebug,
+// runtime, runtime/metrics, and cmd/go/internal/load.
+package godebugs
+
+// An Info describes a single known GODEBUG setting.
+type Info struct {
+       Name    string // name of the setting ("panicnil")
+       Package string // package that uses the setting ("runtime")
+       Changed int    // minor version when default changed, if any; 21 means Go 1.21
+       Old     string // value that restores behavior prior to Changed
+       Opaque  bool   // setting does not export information to runtime/metrics using [internal/godebug.Setting.IncNonDefault]
+}
+
+// All is the table of known settings, sorted by Name.
+//
+// Note: After adding entries to this table, run 'go generate runtime/metrics'
+// to update the runtime/metrics doc comment.
+// (Otherwise the runtime/metrics test will fail.)
+//
+// Note: After adding entries to this table, update the list in doc/godebug.md as well.
+// (Otherwise the test in this package will fail.)
+var All = []Info{
+       {Name: "execerrdot", Package: "os/exec"},
+       {Name: "http2client", Package: "net/http"},
+       {Name: "http2debug", Package: "net/http", Opaque: true},
+       {Name: "http2server", Package: "net/http"},
+       {Name: "installgoroot", Package: "go/build"},
+       {Name: "jstmpllitinterp", Package: "html/template"},
+       //{Name: "multipartfiles", Package: "mime/multipart"},
+       {Name: "multipartmaxheaders", Package: "mime/multipart"},
+       {Name: "multipartmaxparts", Package: "mime/multipart"},
+       {Name: "netdns", Package: "net", Opaque: true},
+       {Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
+       {Name: "randautoseed", Package: "math/rand"},
+       {Name: "tarinsecurepath", Package: "archive/tar"},
+       {Name: "x509sha1", Package: "crypto/x509"},
+       {Name: "x509usefallbackroots", Package: "crypto/x509"},
+       {Name: "zipinsecurepath", Package: "archive/zip"},
+}
+
+// Lookup returns the Info with the given name.
+func Lookup(name string) *Info {
+       // binary search, avoiding import of sort.
+       lo := 0
+       hi := len(All)
+       for lo < hi {
+               m := lo + (hi-lo)>>1
+               mid := All[m].Name
+               if name == mid {
+                       return &All[m]
+               }
+               if name < mid {
+                       hi = m
+               } else {
+                       lo = m + 1
+               }
+       }
+       return nil
+}
index 0e6852f7299188ac45cc2471f1e14d3f6bbd964a..2f97c2e6694286ef120f2c1067f16395018d5589 100644 (file)
@@ -66,7 +66,7 @@ var (
        valSafe = safeMap()         // non-nil in safe+leaky mode
 )
 
-var intern = godebug.New("intern")
+var intern = godebug.New("#intern")
 
 // safeMap returns a non-nil map if we're in safe-but-leaky mode,
 // as controlled by GODEBUG=intern=leaky
index 86a8d2bfcf81112bb4e8bcb3884dd7ede29d089c..f8258a961c55994048332ba19488b9f5d65fc579 100644 (file)
@@ -34,7 +34,7 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
 }
 
 var (
-       multipartFiles    = godebug.New("multipartfiles")
+       multipartFiles    = godebug.New("#multipartfiles") // TODO: document and remove #
        multipartMaxParts = godebug.New("multipartmaxparts")
 )
 
@@ -48,7 +48,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
        combineFiles := true
        if multipartFiles.Value() == "distinct" {
                combineFiles = false
-               multipartFiles.IncNonDefault()
+               // multipartFiles.IncNonDefault() // TODO: uncomment after documenting
        }
        maxParts := 1000
        if s := multipartMaxParts.Value(); s != "" {
index 2f4bdffe9c74577410fa09dbf4bbcc6da1cc46fd..138be29ecfba6d171aa3d5745dca899e649be4f4 100644 (file)
@@ -348,7 +348,7 @@ type ctxResult struct {
        timer *time.Timer
 }
 
-var execwait = godebug.New("execwait")
+var execwait = godebug.New("#execwait")
 var execerrdot = godebug.New("execerrdot")
 
 // Command returns the Cmd struct to execute the named program with
index d154acce713cb2b516957f671a6d2cf5251dfde3..4a51ae573f66306ba6fbcdc47f5aed58e4f7e99a 100644 (file)
@@ -7,6 +7,7 @@ package runtime
 // Metrics implementation exported to runtime/metrics.
 
 import (
+       "internal/godebugs"
        "unsafe"
 )
 
@@ -286,20 +287,6 @@ func initMetrics() {
                                out.scalar = uint64(startingStackSize)
                        },
                },
-               "/godebug/non-default-behavior/execerrdot:events":           {compute: compute0},
-               "/godebug/non-default-behavior/http2client:events":          {compute: compute0},
-               "/godebug/non-default-behavior/http2server:events":          {compute: compute0},
-               "/godebug/non-default-behavior/installgoroot:events":        {compute: compute0},
-               "/godebug/non-default-behavior/jstmpllitinterp:events":      {compute: compute0},
-               "/godebug/non-default-behavior/multipartfiles:events":       {compute: compute0},
-               "/godebug/non-default-behavior/multipartmaxheaders:events":  {compute: compute0},
-               "/godebug/non-default-behavior/multipartmaxparts:events":    {compute: compute0},
-               "/godebug/non-default-behavior/panicnil:events":             {compute: compute0},
-               "/godebug/non-default-behavior/randautoseed:events":         {compute: compute0},
-               "/godebug/non-default-behavior/tarinsecurepath:events":      {compute: compute0},
-               "/godebug/non-default-behavior/x509sha1:events":             {compute: compute0},
-               "/godebug/non-default-behavior/x509usefallbackroots:events": {compute: compute0},
-               "/godebug/non-default-behavior/zipinsecurepath:events":      {compute: compute0},
                "/memory/classes/heap/free:bytes": {
                        deps: makeStatDepSet(heapStatsDep),
                        compute: func(in *statAggregate, out *metricValue) {
@@ -432,6 +419,13 @@ func initMetrics() {
                        },
                },
        }
+
+       for _, info := range godebugs.All {
+               if !info.Opaque {
+                       metrics["/godebug/non-default-behavior/"+info.Name+":events"] = metricData{compute: compute0}
+               }
+       }
+
        metricsInit = true
 }
 
@@ -447,10 +441,6 @@ func (f metricReader) compute(_ *statAggregate, out *metricValue) {
        out.scalar = f()
 }
 
-var godebugNonDefaults = []string{
-       "panicnil",
-}
-
 //go:linkname godebug_registerMetric internal/godebug.registerMetric
 func godebug_registerMetric(name string, read func() uint64) {
        metricsLock()
index a06c017b7f90f3d2d81f5e424b2ce0b743818ed8..9f486d1367b90381833ccd2db78dcfff02ee9eec 100644 (file)
@@ -4,6 +4,8 @@
 
 package metrics
 
+import "internal/godebugs"
+
 // Description describes a runtime metric.
 type Description struct {
        // Name is the full name of the metric which includes the unit.
@@ -49,7 +51,7 @@ type Description struct {
 }
 
 // The English language descriptions below must be kept in sync with the
-// descriptions of each metric in doc.go.
+// descriptions of each metric in doc.go by running 'go generate'.
 var allDesc = []Description{
        {
                Name:        "/cgo/go-to-c-calls:calls",
@@ -277,104 +279,6 @@ var allDesc = []Description{
                Kind:        KindUint64,
                Cumulative:  false,
        },
-       {
-               Name: "/godebug/non-default-behavior/execerrdot:events",
-               Description: "The number of non-default behaviors executed by the os/exec package " +
-                       "due to a non-default GODEBUG=execerrdot=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/http2client:events",
-               Description: "The number of non-default behaviors executed by the net/http package " +
-                       "due to a non-default GODEBUG=http2client=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/http2server:events",
-               Description: "The number of non-default behaviors executed by the net/http package " +
-                       "due to a non-default GODEBUG=http2server=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/installgoroot:events",
-               Description: "The number of non-default behaviors executed by the go/build package " +
-                       "due to a non-default GODEBUG=installgoroot=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/jstmpllitinterp:events",
-               Description: "The number of non-default behaviors executed by the html/template" +
-                       "package due to a non-default GODEBUG=jstmpllitinterp=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/multipartfiles:events",
-               Description: "The number of non-default behaviors executed by the mime/multipart package " +
-                       "due to a non-default GODEBUG=multipartfiles=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/multipartmaxheaders:events",
-               Description: "The number of non-default behaviors executed by the mime/multipart package " +
-                       "due to a non-default GODEBUG=multipartmaxheaders=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/multipartmaxparts:events",
-               Description: "The number of non-default behaviors executed by the mime/multipart package " +
-                       "due to a non-default GODEBUG=multipartmaxparts=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/panicnil:events",
-               Description: "The number of non-default behaviors executed by the runtime package " +
-                       "due to a non-default GODEBUG=panicnil=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/randautoseed:events",
-               Description: "The number of non-default behaviors executed by the math/rand package " +
-                       "due to a non-default GODEBUG=randautoseed=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/tarinsecurepath:events",
-               Description: "The number of non-default behaviors executed by the archive/tar package " +
-                       "due to a non-default GODEBUG=tarinsecurepath=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/x509sha1:events",
-               Description: "The number of non-default behaviors executed by the crypto/x509 package " +
-                       "due to a non-default GODEBUG=x509sha1=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/x509usefallbackroots:events",
-               Description: "The number of non-default behaviors executed by the crypto/x509 package " +
-                       "due to a non-default GODEBUG=x509usefallbackroots=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
-       {
-               Name: "/godebug/non-default-behavior/zipinsecurepath:events",
-               Description: "The number of non-default behaviors executed by the archive/zip package " +
-                       "due to a non-default GODEBUG=zipinsecurepath=... setting.",
-               Kind:       KindUint64,
-               Cumulative: true,
-       },
        {
                Name: "/memory/classes/heap/free:bytes",
                Description: "Memory that is completely free and eligible to be returned to the underlying system, " +
@@ -472,6 +376,30 @@ var allDesc = []Description{
        },
 }
 
+func init() {
+       // Insert all the the non-default-reporting GODEBUGs into the table,
+       // preserving the overall sort order.
+       i := 0
+       for i < len(allDesc) && allDesc[i].Name < "/godebug/" {
+               i++
+       }
+       more := make([]Description, i, len(allDesc)+len(godebugs.All))
+       copy(more, allDesc)
+       for _, info := range godebugs.All {
+               if !info.Opaque {
+                       more = append(more, Description{
+                               Name: "/godebug/non-default-behavior/" + info.Name + ":events",
+                               Description: "The number of non-default behaviors executed by the " +
+                                       info.Package + " package " + "due to a non-default " +
+                                       "GODEBUG=" + info.Name + "=... setting.",
+                               Kind:       KindUint64,
+                               Cumulative: true,
+                       })
+               }
+       }
+       allDesc = append(more, allDesc[i:]...)
+}
+
 // All returns a slice of containing metric descriptions for all supported metrics.
 func All() []Description {
        return allDesc
index 68bbf5a3cea165f80b017dc373fc02361b9a9fe0..ce6e944d8cbc9f249862a1adcc111999c4f31bd1 100644 (file)
@@ -221,14 +221,9 @@ Below is the full list of supported metrics, ordered lexicographically.
 
        /godebug/non-default-behavior/jstmpllitinterp:events
                The number of non-default behaviors executed by
-               the html/templatepackage due to a non-default
+               the html/template package due to a non-default
                GODEBUG=jstmpllitinterp=... setting.
 
-       /godebug/non-default-behavior/multipartfiles:events
-               The number of non-default behaviors executed by
-               the mime/multipart package due to a non-default
-               GODEBUG=multipartfiles=... setting.
-
        /godebug/non-default-behavior/multipartmaxheaders:events
                The number of non-default behaviors executed by
                the mime/multipart package due to a non-default