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