1
2
3
4
5 package load
6
7 import (
8 "errors"
9 "fmt"
10 "go/build"
11 "internal/godebugs"
12 "maps"
13 "sort"
14 "strconv"
15 "strings"
16
17 "cmd/go/internal/fips140"
18 "cmd/go/internal/gover"
19 "cmd/go/internal/modload"
20 )
21
22 var ErrNotGoDebug = errors.New("not //go:debug line")
23
24 func ParseGoDebug(text string) (key, value string, err error) {
25 if !strings.HasPrefix(text, "//go:debug") {
26 return "", "", ErrNotGoDebug
27 }
28 i := strings.IndexAny(text, " \t")
29 if i < 0 {
30 if strings.TrimSpace(text) == "//go:debug" {
31 return "", "", fmt.Errorf("missing key=value")
32 }
33 return "", "", ErrNotGoDebug
34 }
35 k, v, ok := strings.Cut(strings.TrimSpace(text[i:]), "=")
36 if !ok {
37 return "", "", fmt.Errorf("missing key=value")
38 }
39 if err := modload.CheckGodebug("//go:debug setting", k, v); err != nil {
40 return "", "", err
41 }
42 return k, v, nil
43 }
44
45 func defaultGODEBUGGoVersion(loaderstate *modload.State, p *Package) string {
46 if !loaderstate.Enabled() {
47
48 return "1.20"
49 }
50 if loaderstate.RootMode == modload.NoRoot && p.Module != nil {
51
52
53
54
55 if goVersion := p.Module.GoVersion; goVersion != "" {
56 return goVersion
57 }
58 return "1.20"
59 }
60 return loaderstate.MainModules.GoVersion(loaderstate)
61 }
62
63
64
65
66 func defaultGODEBUG(loaderstate *modload.State, p *Package, directives, testDirectives, xtestDirectives []build.Directive) string {
67 if p.Name != "main" {
68 return ""
69 }
70
71 goVersion := defaultGODEBUGGoVersion(loaderstate, p)
72
73 var m map[string]string
74
75
76
77 if fips140.Enabled() {
78 m = map[string]string{"fips140": "on"}
79 }
80
81
82 for _, g := range loaderstate.MainModules.Godebugs(loaderstate) {
83 if m == nil {
84 m = make(map[string]string)
85 }
86 m[g.Key] = g.Value
87 }
88
89
90 for _, list := range [][]build.Directive{p.Internal.Build.Directives, directives, testDirectives, xtestDirectives} {
91 for _, d := range list {
92 k, v, err := ParseGoDebug(d.Text)
93 if err != nil {
94 continue
95 }
96 if m == nil {
97 m = make(map[string]string)
98 }
99 m[k] = v
100 }
101 }
102 if v, ok := m["default"]; ok {
103 delete(m, "default")
104 v = strings.TrimPrefix(v, "go")
105 if gover.IsValid(v) {
106 goVersion = v
107 }
108 }
109
110 defaults := godebugForGoVersion(goVersion)
111 if defaults != nil {
112
113 maps.Copy(defaults, m)
114 m = defaults
115 }
116
117 keys := make([]string, 0, len(m))
118 for k := range m {
119 keys = append(keys, k)
120 }
121 sort.Strings(keys)
122 var b strings.Builder
123 for _, k := range keys {
124 if b.Len() > 0 {
125 b.WriteString(",")
126 }
127 b.WriteString(k)
128 b.WriteString("=")
129 b.WriteString(m[k])
130 }
131 return b.String()
132 }
133
134 func godebugForGoVersion(v string) map[string]string {
135 if strings.Count(v, ".") >= 2 {
136 i := strings.Index(v, ".")
137 j := i + 1 + strings.Index(v[i+1:], ".")
138 v = v[:j]
139 }
140
141 if !strings.HasPrefix(v, "1.") {
142 return nil
143 }
144 n, err := strconv.Atoi(v[len("1."):])
145 if err != nil {
146 return nil
147 }
148
149 def := make(map[string]string)
150 for _, info := range godebugs.All {
151 if n < info.Changed {
152 def[info.Name] = info.Old
153 }
154 }
155 return def
156 }
157
View as plain text