]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/load/godebug.go
cmd/go: add check for unknown godebug setting
[gostls13.git] / src / cmd / go / internal / load / godebug.go
1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package load
6
7 import (
8         "cmd/go/internal/modload"
9         "errors"
10         "fmt"
11         "go/build"
12         "internal/godebugs"
13         "sort"
14         "strconv"
15         "strings"
16 )
17
18 var ErrNotGoDebug = errors.New("not //go:debug line")
19
20 func ParseGoDebug(text string) (key, value string, err error) {
21         if !strings.HasPrefix(text, "//go:debug") {
22                 return "", "", ErrNotGoDebug
23         }
24         i := strings.IndexAny(text, " \t")
25         if i < 0 {
26                 if strings.TrimSpace(text) == "//go:debug" {
27                         return "", "", fmt.Errorf("missing key=value")
28                 }
29                 return "", "", ErrNotGoDebug
30         }
31         k, v, ok := strings.Cut(strings.TrimSpace(text[i:]), "=")
32         if !ok {
33                 return "", "", fmt.Errorf("missing key=value")
34         }
35         if strings.ContainsAny(k, " \t") {
36                 return "", "", fmt.Errorf("key contains space")
37         }
38         if strings.ContainsAny(v, " \t") {
39                 return "", "", fmt.Errorf("value contains space")
40         }
41         if strings.ContainsAny(k, ",") {
42                 return "", "", fmt.Errorf("key contains comma")
43         }
44         if strings.ContainsAny(v, ",") {
45                 return "", "", fmt.Errorf("value contains comma")
46         }
47
48         for _, info := range godebugs.All {
49                 if k == info.Name {
50                         return k, v, nil
51                 }
52         }
53         return "", "", fmt.Errorf("unknown //go:debug setting %q", k)
54 }
55
56 // defaultGODEBUG returns the default GODEBUG setting for the main package p.
57 // When building a test binary, directives, testDirectives, and xtestDirectives
58 // list additional directives from the package under test.
59 func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []build.Directive) string {
60         if p.Name != "main" {
61                 return ""
62         }
63         goVersion := modload.MainModules.GoVersion()
64         if modload.RootMode == modload.NoRoot && p.Module != nil {
65                 // This is go install pkg@version or go run pkg@version.
66                 // Use the Go version from the package.
67                 // If there isn't one, then
68                 goVersion = p.Module.GoVersion
69                 if goVersion == "" {
70                         goVersion = "1.20"
71                 }
72         }
73
74         m := godebugForGoVersion(goVersion)
75         for _, list := range [][]build.Directive{p.Internal.Build.Directives, directives, testDirectives, xtestDirectives} {
76                 for _, d := range list {
77                         k, v, err := ParseGoDebug(d.Text)
78                         if err != nil {
79                                 continue
80                         }
81                         if m == nil {
82                                 m = make(map[string]string)
83                         }
84                         m[k] = v
85                 }
86         }
87         var keys []string
88         for k := range m {
89                 keys = append(keys, k)
90         }
91         sort.Strings(keys)
92         var b strings.Builder
93         for _, k := range keys {
94                 if b.Len() > 0 {
95                         b.WriteString(",")
96                 }
97                 b.WriteString(k)
98                 b.WriteString("=")
99                 b.WriteString(m[k])
100         }
101         return b.String()
102 }
103
104 func godebugForGoVersion(v string) map[string]string {
105         if strings.Count(v, ".") >= 2 {
106                 i := strings.Index(v, ".")
107                 j := i + 1 + strings.Index(v[i+1:], ".")
108                 v = v[:j]
109         }
110
111         if !strings.HasPrefix(v, "1.") {
112                 return nil
113         }
114         n, err := strconv.Atoi(v[len("1."):])
115         if err != nil {
116                 return nil
117         }
118
119         def := make(map[string]string)
120         for _, info := range godebugs.All {
121                 if n < info.Changed {
122                         def[info.Name] = info.Old
123                 }
124         }
125         return def
126 }