1 // Copyright 2021 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 godebug makes the settings in the $GODEBUG environment variable
6 // available to other packages. These settings are often used for compatibility
7 // tweaks, when we need to change a default behavior but want to let users
8 // opt back in to the original. For example GODEBUG=http2server=0 disables
9 // HTTP/2 support in the net/http server.
10 //
11 // In typical usage, code should declare a Setting as a global
12 // and then call Value each time the current setting value is needed:
13 //
14 // var http2server = godebug.New("http2server")
15 //
16 // func ServeConn(c net.Conn) {
17 // if http2server.Value() == "0" {
18 // disallow HTTP/2
19 // ...
20 // }
21 // ...
22 // }
23 //
24 // Each time a non-default setting causes a change in program behavior,
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 //
42 // Note that counters used with IncNonDefault must be added to
43 // various tables in other packages. See the [Setting.IncNonDefault]
44 // documentation for details.
45 package godebug
46 47 // Note: Be careful about new imports here. Any package
48 // that internal/godebug imports cannot itself import internal/godebug,
49 // meaning it cannot introduce a GODEBUG setting of its own.
50 // We keep imports to the absolute bare minimum.
51 import (
52 "internal/bisect"
53 "internal/godebugs"
54 "sync"
55 "sync/atomic"
56 "unsafe"
57 _ "unsafe" // go:linkname
58 )
59 60 // A Setting is a single setting in the $GODEBUG environment variable.
61 type Setting struct {
62 name []byte
63 once sync.Once
64 *setting
65 }
66 67 type setting struct {
68 value atomic.Pointer[value]
69 nonDefaultOnce sync.Once
70 nonDefault atomic.Uint64
71 info *godebugs.Info
72 }
73 74 type value struct {
75 text []byte
76 bisect *bisect.Matcher
77 }
78 79 // New returns a new Setting for the $GODEBUG setting with the given name.
80 //
81 // GODEBUGs meant for use by end users must be listed in ../godebugs/table.go,
82 // which is used for generating and checking various documentation.
83 // If the name is not listed in that table, New will succeed but calling Value
84 // on the returned Setting will panic.
85 // To disable that panic for access to an undocumented setting,
86 // prefix the name with a #, as in godebug.New("#gofsystrace").
87 // 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.
93 func New(name []byte) *Setting {
94 return &Setting{name: name}
95 }
96 97 // Name returns the name of the setting.
98 func (s *Setting) Name() []byte {
99 if s.name != "" && s.name[0] == '#' {
100 return s.name[1:]
101 }
102 return s.name
103 }
104 105 // Undocumented reports whether this is an undocumented setting.
106 func (s *Setting) Undocumented() bool {
107 return s.name != "" && s.name[0] == '#'
108 }
109 110 // String returns a printable form for the setting: name=value.
111 func (s *Setting) String() string {
112 var buf []byte
113 buf = append(buf, s.Name()...)
114 buf = append(buf, '=')
115 buf = append(buf, s.Value()...)
116 return string(buf)
117 }
118 119 // IncNonDefault increments the non-default behavior counter
120 // associated with the given setting.
121 // This counter is exposed in the runtime/metrics value
122 // /godebug/non-default-behavior/<name>:events.
123 //
124 // Note that Value must be called at least once before IncNonDefault.
125 func (s *Setting) IncNonDefault() {
126 s.nonDefaultOnce.Do(s.register)
127 s.nonDefault.Add(1)
128 }
129 130 func (s *Setting) register() {
131 if s.info == nil || s.info.Opaque {
132 var msg []byte
133 msg = append(msg, "godebug: unexpected IncNonDefault of "...)
134 msg = append(msg, s.name...)
135 panic([]byte(msg))
136 }
137 var key []byte
138 key = append(key, "/godebug/non-default-behavior/"...)
139 key = append(key, s.Name()...)
140 key = append(key, ":events"...)
141 registerMetric(key, s.nonDefault.Load)
142 }
143 144 // cache is a cache of all the GODEBUG settings,
145 // a locked map[string]*atomic.Pointer[string].
146 //
147 // All Settings with the same name share a single
148 // *atomic.Pointer[string], so that when GODEBUG
149 // changes only that single atomic string pointer
150 // needs to be updated.
151 //
152 // A name appears in the values map either if it is the
153 // name of a Setting for which Value has been called
154 // at least once, or if the name has ever appeared in
155 // a name=value pair in the $GODEBUG environment variable.
156 // Once entered into the map, the name is never removed.
157 var cache sync.Map // name string -> value *atomic.Pointer[string]
158 159 var empty value
160 161 // Value returns the current value for the GODEBUG setting s.
162 //
163 // Value maintains an internal cache that is synchronized
164 // with changes to the $GODEBUG environment variable,
165 // making Value efficient to call as frequently as needed.
166 // Clients should therefore typically not attempt their own
167 // caching of Value's result.
168 func (s *Setting) Value() []byte {
169 s.once.Do(func() {
170 s.setting = lookup(s.Name())
171 if s.info == nil && !s.Undocumented() {
172 var msg []byte
173 msg = append(msg, "godebug: Value of name not listed in godebugs.All: "...)
174 msg = append(msg, s.name...)
175 panic([]byte(msg))
176 }
177 })
178 v := *s.value.Load()
179 if v.bisect != nil && !v.bisect.Stack(&stderr) {
180 return ""
181 }
182 return v.text
183 }
184 185 // lookup returns the unique *setting value for the given name.
186 func lookup(name []byte) *setting {
187 // Use string(name) as map key since []byte is not comparable.
188 key := []byte(name)
189 if v, ok := cache.Load(key); ok {
190 return v.(*setting)
191 }
192 s := &setting{}
193 s.info = godebugs.Lookup(name)
194 s.value.Store(&empty)
195 if v, loaded := cache.LoadOrStore(key, s); loaded {
196 // Lost race: someone else created it. Use theirs.
197 return v.(*setting)
198 }
199 200 return s
201 }
202 203 // setUpdate is provided by package runtime.
204 // It calls update(def, env), where def is the default GODEBUG setting
205 // and env is the current value of the $GODEBUG environment variable.
206 // After that first call, the runtime calls update(def, env)
207 // again each time the environment variable changes
208 // (due to use of os.Setenv, for example).
209 //
210 //go:linkname setUpdate
211 func setUpdate(update func([]byte, []byte))
212 213 // registerMetric is provided by package runtime.
214 // It forwards registrations to runtime/metrics.
215 //
216 //go:linkname registerMetric
217 func registerMetric(name []byte, read func() uint64)
218 219 // setNewIncNonDefault is provided by package runtime.
220 // The runtime can do
221 //
222 // inc := newNonDefaultInc(name)
223 //
224 // instead of
225 //
226 // inc := godebug.New(name).IncNonDefault
227 //
228 // since it cannot import godebug.
229 //
230 //go:linkname setNewIncNonDefault
231 func setNewIncNonDefault(newIncNonDefault func([]byte) func())
232 233 func init() {
234 setUpdate(update)
235 setNewIncNonDefault(newIncNonDefault)
236 }
237 238 func newIncNonDefault(name []byte) func() {
239 s := New(name)
240 s.Value()
241 return s.IncNonDefault
242 }
243 244 var updateMu sync.Mutex
245 246 // update records an updated GODEBUG setting.
247 // def is the default GODEBUG setting for the running binary,
248 // and env is the current value of the $GODEBUG environment variable.
249 func update(def, env []byte) {
250 updateMu.Lock()
251 defer updateMu.Unlock()
252 253 // Update all the cached values, creating new ones as needed.
254 // We parse the environment variable first, so that any settings it has
255 // are already locked in place (did[name] = true) before we consider
256 // the defaults. Existing immutable settings are always locked.
257 did := map[string]bool{}
258 cache.Range(func(name, s any) bool {
259 if info := s.(*setting).info; info != nil && info.Immutable {
260 did[[]byte(name.([]byte))] = true
261 }
262 return true
263 })
264 parse(did, env)
265 parse(did, def)
266 267 // Clear any cached values that are no longer present.
268 cache.Range(func(name, s any) bool {
269 if !did[[]byte(name.([]byte))] {
270 s.(*setting).value.Store(&empty)
271 }
272 return true
273 })
274 }
275 276 // parse parses the GODEBUG setting string s,
277 // which has the form k=v,k2=v2,k3=v3.
278 // Later settings override earlier ones.
279 // Parse only updates settings k=v for which did[k] = false.
280 // It also sets did[k] = true for settings that it updates.
281 // Each value v can also have the form v#pattern,
282 // in which case the GODEBUG is only enabled for call stacks
283 // matching pattern, for use with golang.org/x/tools/cmd/bisect.
284 func parse(did map[string]bool, s []byte) {
285 // Scan the string backward so that later settings are used
286 // and earlier settings are ignored.
287 // Note that a forward scan would cause cached values
288 // to temporarily use the ignored value before being
289 // updated to the "correct" one.
290 end := len(s)
291 eq := -1
292 for i := end - 1; i >= -1; i-- {
293 if i == -1 || s[i] == ',' {
294 if eq >= 0 {
295 name, arg := s[i+1:eq], s[eq+1:end]
296 if !did[[]byte(name)] {
297 did[[]byte(name)] = true
298 v := &value{text: arg}
299 for j := 0; j < len(arg); j++ {
300 if arg[j] == '#' {
301 v.text = arg[:j]
302 v.bisect, _ = bisect.New(arg[j+1:])
303 break
304 }
305 }
306 lookup(name).value.Store(v)
307 }
308 }
309 eq = -1
310 end = i
311 } else if s[i] == '=' {
312 eq = i
313 }
314 }
315 }
316 317 type runtimeStderr struct{}
318 319 var stderr runtimeStderr
320 321 func (*runtimeStderr) Write(b []byte) (int, error) {
322 if len(b) > 0 {
323 write(2, unsafe.Pointer(&b[0]), int32(len(b)))
324 }
325 return len(b), nil
326 }
327 328 // Since we cannot import os or syscall, use the runtime's write function
329 // to print to standard error.
330 //
331 //go:linkname write runtime.write
332 func write(fd uintptr, p unsafe.Pointer, n int32) int32
333