Skip to content

Commit 74726de

Browse files
committed
internal/godebugs: test for use of IncNonDefault
A few recent godebugs are missing IncNonDefault uses. Test for that, so that people remember to do it. Filed bugs for the missing ones. For #66215. For #66216. For #66217. Change-Id: Ia3fd10fd108e1b003bb30a8bc2f83995c768fab6 Reviewed-on: https://go-review.googlesource.com/c/go/+/570275 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 065c5d2 commit 74726de

File tree

9 files changed

+100
-49
lines changed

9 files changed

+100
-49
lines changed

src/cmd/go/internal/cache/cache.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,22 +159,22 @@ var DebugTest = false
159159
func init() { initEnv() }
160160

161161
var (
162-
goCacheVerify = godebug.New("gocacheverify")
163-
goDebugHash = godebug.New("gocachehash")
164-
goCacheTest = godebug.New("gocachetest")
162+
gocacheverify = godebug.New("gocacheverify")
163+
gocachehash = godebug.New("gocachehash")
164+
gocachetest = godebug.New("gocachetest")
165165
)
166166

167167
func initEnv() {
168-
if goCacheVerify.Value() == "1" {
169-
goCacheVerify.IncNonDefault()
168+
if gocacheverify.Value() == "1" {
169+
gocacheverify.IncNonDefault()
170170
verify = true
171171
}
172-
if goDebugHash.Value() == "1" {
173-
goDebugHash.IncNonDefault()
172+
if gocachehash.Value() == "1" {
173+
gocachehash.IncNonDefault()
174174
debugHash = true
175175
}
176-
if goCacheTest.Value() == "1" {
177-
goCacheTest.IncNonDefault()
176+
if gocachetest.Value() == "1" {
177+
gocachetest.IncNonDefault()
178178
DebugTest = true
179179
}
180180
}

src/crypto/x509/x509.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ func isIA5String(s string) error {
11011101
return nil
11021102
}
11031103

1104-
var usePoliciesField = godebug.New("x509usepolicies")
1104+
var x509usepolicies = godebug.New("x509usepolicies")
11051105

11061106
func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
11071107
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
@@ -1188,7 +1188,7 @@ func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKe
11881188
n++
11891189
}
11901190

1191-
usePolicies := usePoliciesField.Value() == "1"
1191+
usePolicies := x509usepolicies.Value() == "1"
11921192
if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) &&
11931193
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
11941194
ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers)
@@ -1381,8 +1381,8 @@ func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectI
13811381

13821382
b := cryptobyte.NewBuilder(make([]byte, 0, 128))
13831383
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) {
1384-
if usePoliciesField.Value() == "1" {
1385-
usePoliciesField.IncNonDefault()
1384+
if x509usepolicies.Value() == "1" {
1385+
x509usepolicies.IncNonDefault()
13861386
for _, v := range policies {
13871387
child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) {
13881388
child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) {

src/internal/godebug/godebug.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,23 @@
2222
// }
2323
//
2424
// Each time a non-default setting causes a change in program behavior,
25-
// code should call [Setting.IncNonDefault] to increment a counter that can
26-
// be reported by [runtime/metrics.Read].
25+
// code must call [Setting.IncNonDefault] to increment a counter that can
26+
// be reported by [runtime/metrics.Read]. The call must only happen when
27+
// the program executes a non-default behavior, not just when the setting
28+
// is set to a non-default value. This is occasionally (but very rarely)
29+
// infeasible, in which case the internal/godebugs table entry must set
30+
// Opaque: true, and the documentation in doc/godebug.md should
31+
// mention that metrics are unavailable.
32+
//
33+
// Conventionally, the global variable representing a godebug is named
34+
// for the godebug itself, with no case changes:
35+
//
36+
// var gotypesalias = godebug.New("gotypesalias") // this
37+
// var goTypesAlias = godebug.New("gotypesalias") // NOT THIS
38+
//
39+
// The test in internal/godebugs that checks for use of IncNonDefault
40+
// requires the use of this convention.
41+
//
2742
// Note that counters used with IncNonDefault must be added to
2843
// various tables in other packages. See the [Setting.IncNonDefault]
2944
// documentation for details.
@@ -70,6 +85,11 @@ type value struct {
7085
// To disable that panic for access to an undocumented setting,
7186
// prefix the name with a #, as in godebug.New("#gofsystrace").
7287
// The # is a signal to New but not part of the key used in $GODEBUG.
88+
//
89+
// Note that almost all settings should arrange to call [IncNonDefault] precisely
90+
// when program behavior is changing from the default due to the setting
91+
// (not just when the setting is different, but when program behavior changes).
92+
// See the [internal/godebug] package comment for more.
7393
func New(name string) *Setting {
7494
return &Setting{name: name}
7595
}

src/internal/godebugs/godebugs_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@ import (
88
"internal/godebugs"
99
"internal/testenv"
1010
"os"
11+
"os/exec"
12+
"path/filepath"
13+
"regexp"
1114
"runtime"
1215
"strings"
1316
"testing"
1417
)
1518

1619
func TestAll(t *testing.T) {
20+
testenv.MustHaveGoBuild(t)
21+
1722
data, err := os.ReadFile("../../../doc/godebug.md")
1823
if err != nil {
1924
if os.IsNotExist(err) && (testenv.Builder() == "" || runtime.GOOS != "linux") {
@@ -23,6 +28,8 @@ func TestAll(t *testing.T) {
2328
}
2429
doc := string(data)
2530

31+
incs := incNonDefaults(t)
32+
2633
last := ""
2734
for _, info := range godebugs.All {
2835
if info.Name <= last {
@@ -42,5 +49,46 @@ func TestAll(t *testing.T) {
4249
if !strings.Contains(doc, "`"+info.Name+"`") {
4350
t.Errorf("Name=%s not documented in doc/godebug.md", info.Name)
4451
}
52+
if !info.Opaque && !incs[info.Name] {
53+
t.Errorf("Name=%s missing IncNonDefault calls; see 'go doc internal/godebug'", info.Name)
54+
}
55+
}
56+
}
57+
58+
var incNonDefaultRE = regexp.MustCompile(`([\pL\p{Nd}_]+)\.IncNonDefault\(\)`)
59+
60+
func incNonDefaults(t *testing.T) map[string]bool {
61+
// Build list of all files importing internal/godebug.
62+
// Tried a more sophisticated search in go list looking for
63+
// imports containing "internal/godebug", but that turned
64+
// up a bug in go list instead. #66218
65+
out, err := exec.Command("go", "list", "-f={{.Dir}}", "std", "cmd").CombinedOutput()
66+
if err != nil {
67+
t.Fatalf("go list: %v\n%s", err, out)
68+
}
69+
70+
seen := map[string]bool{}
71+
for _, dir := range strings.Split(string(out), "\n") {
72+
if dir == "" {
73+
continue
74+
}
75+
files, err := os.ReadDir(dir)
76+
if err != nil {
77+
t.Fatal(err)
78+
}
79+
for _, file := range files {
80+
name := file.Name()
81+
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
82+
continue
83+
}
84+
data, err := os.ReadFile(filepath.Join(dir, name))
85+
if err != nil {
86+
t.Fatal(err)
87+
}
88+
for _, m := range incNonDefaultRE.FindAllSubmatch(data, -1) {
89+
seen[string(m[1])] = true
90+
}
91+
}
4592
}
93+
return seen
4694
}

src/internal/godebugs/table.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ var All = []Info{
2929
{Name: "gocachehash", Package: "cmd/go"},
3030
{Name: "gocachetest", Package: "cmd/go"},
3131
{Name: "gocacheverify", Package: "cmd/go"},
32-
{Name: "gotypesalias", Package: "go/types"},
32+
{Name: "gotypesalias", Package: "go/types", Opaque: true}, // bug #66216: remove Opaque
3333
{Name: "http2client", Package: "net/http"},
3434
{Name: "http2debug", Package: "net/http", Opaque: true},
3535
{Name: "http2server", Package: "net/http"},
3636
{Name: "httplaxcontentlength", Package: "net/http", Changed: 22, Old: "1"},
3737
{Name: "httpmuxgo121", Package: "net/http", Changed: 22, Old: "1"},
3838
{Name: "installgoroot", Package: "go/build"},
39-
{Name: "jstmpllitinterp", Package: "html/template"},
39+
{Name: "jstmpllitinterp", Package: "html/template", Opaque: true}, // bug #66217: remove Opaque
4040
//{Name: "multipartfiles", Package: "mime/multipart"},
4141
{Name: "multipartmaxheaders", Package: "mime/multipart"},
4242
{Name: "multipartmaxparts", Package: "mime/multipart"},
@@ -49,8 +49,8 @@ var All = []Info{
4949
{Name: "tlsmaxrsasize", Package: "crypto/tls"},
5050
{Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"},
5151
{Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"},
52-
{Name: "winreadlinkvolume", Package: "os", Changed: 22, Old: "0"},
53-
{Name: "winsymlink", Package: "os", Changed: 22, Old: "0"},
52+
{Name: "winreadlinkvolume", Package: "os", Changed: 22, Old: "0", Opaque: true}, // bug #66215: remove Opaque
53+
{Name: "winsymlink", Package: "os", Changed: 22, Old: "0", Opaque: true}, // bug #66215: remove Opaque
5454
{Name: "x509sha1", Package: "crypto/x509"},
5555
{Name: "x509usefallbackroots", Package: "crypto/x509"},
5656
{Name: "x509usepolicies", Package: "crypto/x509"},

src/mime/multipart/formdata.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
3434
}
3535

3636
var (
37-
multipartFiles = godebug.New("#multipartfiles") // TODO: document and remove #
38-
multipartMaxParts = godebug.New("multipartmaxparts")
37+
multipartfiles = godebug.New("#multipartfiles") // TODO: document and remove #
38+
multipartmaxparts = godebug.New("multipartmaxparts")
3939
)
4040

4141
func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
@@ -46,15 +46,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
4646
)
4747
numDiskFiles := 0
4848
combineFiles := true
49-
if multipartFiles.Value() == "distinct" {
49+
if multipartfiles.Value() == "distinct" {
5050
combineFiles = false
51-
// multipartFiles.IncNonDefault() // TODO: uncomment after documenting
51+
// multipartfiles.IncNonDefault() // TODO: uncomment after documenting
5252
}
5353
maxParts := 1000
54-
if s := multipartMaxParts.Value(); s != "" {
54+
if s := multipartmaxparts.Value(); s != "" {
5555
if v, err := strconv.Atoi(s); err == nil && v >= 0 {
5656
maxParts = v
57-
multipartMaxParts.IncNonDefault()
57+
multipartmaxparts.IncNonDefault()
5858
}
5959
}
6060
maxHeaders := maxMIMEHeaders()

src/mime/multipart/multipart.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,15 @@ type Reader struct {
347347
// including header keys, values, and map overhead.
348348
const maxMIMEHeaderSize = 10 << 20
349349

350-
// multipartMaxHeaders is the maximum number of header entries NextPart will return,
350+
// multipartmaxheaders is the maximum number of header entries NextPart will return,
351351
// as well as the maximum combined total of header entries Reader.ReadForm will return
352352
// in FileHeaders.
353-
var multipartMaxHeaders = godebug.New("multipartmaxheaders")
353+
var multipartmaxheaders = godebug.New("multipartmaxheaders")
354354

355355
func maxMIMEHeaders() int64 {
356-
if s := multipartMaxHeaders.Value(); s != "" {
356+
if s := multipartmaxheaders.Value(); s != "" {
357357
if v, err := strconv.ParseInt(s, 10, 64); err == nil && v >= 0 {
358-
multipartMaxHeaders.IncNonDefault()
358+
multipartmaxheaders.IncNonDefault()
359359
return v
360360
}
361361
}

src/net/http/transfer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ func (bl bodyLocked) Read(p []byte) (n int, err error) {
10431043
return bl.b.readLocked(p)
10441044
}
10451045

1046-
var laxContentLength = godebug.New("httplaxcontentlength")
1046+
var httplaxcontentlength = godebug.New("httplaxcontentlength")
10471047

10481048
// parseContentLength checks that the header is valid and then trims
10491049
// whitespace. It returns -1 if no value is set otherwise the value
@@ -1057,8 +1057,8 @@ func parseContentLength(clHeaders []string) (int64, error) {
10571057
// The Content-Length must be a valid numeric value.
10581058
// See: https://datatracker.ietf.org/doc/html/rfc2616/#section-14.13
10591059
if cl == "" {
1060-
if laxContentLength.Value() == "1" {
1061-
laxContentLength.IncNonDefault()
1060+
if httplaxcontentlength.Value() == "1" {
1061+
httplaxcontentlength.IncNonDefault()
10621062
return -1, nil
10631063
}
10641064
return 0, badStringError("invalid empty Content-Length", cl)

src/runtime/metrics/doc.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,6 @@ Below is the full list of supported metrics, ordered lexicographically.
246246
The number of non-default behaviors executed by the cmd/go
247247
package due to a non-default GODEBUG=gocacheverify=... setting.
248248
249-
/godebug/non-default-behavior/gotypesalias:events
250-
The number of non-default behaviors executed by the go/types
251-
package due to a non-default GODEBUG=gotypesalias=... setting.
252-
253249
/godebug/non-default-behavior/http2client:events
254250
The number of non-default behaviors executed by the net/http
255251
package due to a non-default GODEBUG=http2client=... setting.
@@ -271,11 +267,6 @@ Below is the full list of supported metrics, ordered lexicographically.
271267
The number of non-default behaviors executed by the go/build
272268
package due to a non-default GODEBUG=installgoroot=... setting.
273269
274-
/godebug/non-default-behavior/jstmpllitinterp:events
275-
The number of non-default behaviors executed by
276-
the html/template package due to a non-default
277-
GODEBUG=jstmpllitinterp=... setting.
278-
279270
/godebug/non-default-behavior/multipartmaxheaders:events
280271
The number of non-default behaviors executed by
281272
the mime/multipart package due to a non-default
@@ -319,14 +310,6 @@ Below is the full list of supported metrics, ordered lexicographically.
319310
The number of non-default behaviors executed by the crypto/tls
320311
package due to a non-default GODEBUG=tlsunsafeekm=... setting.
321312
322-
/godebug/non-default-behavior/winreadlinkvolume:events
323-
The number of non-default behaviors executed by the os package
324-
due to a non-default GODEBUG=winreadlinkvolume=... setting.
325-
326-
/godebug/non-default-behavior/winsymlink:events
327-
The number of non-default behaviors executed by the os package
328-
due to a non-default GODEBUG=winsymlink=... setting.
329-
330313
/godebug/non-default-behavior/x509sha1:events
331314
The number of non-default behaviors executed by the crypto/x509
332315
package due to a non-default GODEBUG=x509sha1=... setting.

0 commit comments

Comments
 (0)