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.
45package 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.
51import (
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.
61type Setting struct {
62	name string
63	once sync.Once
64	*setting
65}
66
67type setting struct {
68	value          atomic.Pointer[value]
69	nonDefaultOnce sync.Once
70	nonDefault     atomic.Uint64
71	info           *godebugs.Info
72}
73
74type value struct {
75	text   string
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.
93func New(name string) *Setting {
94	return &Setting{name: name}
95}
96
97// Name returns the name of the setting.
98func (s *Setting) Name() string {
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.
106func (s *Setting) Undocumented() bool {
107	return s.name != "" && s.name[0] == '#'
108}
109
110// String returns a printable form for the setting: name=value.
111func (s *Setting) String() string {
112	return s.Name() + "=" + s.Value()
113}
114
115// IncNonDefault increments the non-default behavior counter
116// associated with the given setting.
117// This counter is exposed in the runtime/metrics value
118// /godebug/non-default-behavior/<name>:events.
119//
120// Note that Value must be called at least once before IncNonDefault.
121func (s *Setting) IncNonDefault() {
122	s.nonDefaultOnce.Do(s.register)
123	s.nonDefault.Add(1)
124}
125
126func (s *Setting) register() {
127	if s.info == nil || s.info.Opaque {
128		panic("godebug: unexpected IncNonDefault of " + s.name)
129	}
130	registerMetric("/godebug/non-default-behavior/"+s.Name()+":events", s.nonDefault.Load)
131}
132
133// cache is a cache of all the GODEBUG settings,
134// a locked map[string]*atomic.Pointer[string].
135//
136// All Settings with the same name share a single
137// *atomic.Pointer[string], so that when GODEBUG
138// changes only that single atomic string pointer
139// needs to be updated.
140//
141// A name appears in the values map either if it is the
142// name of a Setting for which Value has been called
143// at least once, or if the name has ever appeared in
144// a name=value pair in the $GODEBUG environment variable.
145// Once entered into the map, the name is never removed.
146var cache sync.Map // name string -> value *atomic.Pointer[string]
147
148var empty value
149
150// Value returns the current value for the GODEBUG setting s.
151//
152// Value maintains an internal cache that is synchronized
153// with changes to the $GODEBUG environment variable,
154// making Value efficient to call as frequently as needed.
155// Clients should therefore typically not attempt their own
156// caching of Value's result.
157func (s *Setting) Value() string {
158	s.once.Do(func() {
159		s.setting = lookup(s.Name())
160		if s.info == nil && !s.Undocumented() {
161			panic("godebug: Value of name not listed in godebugs.All: " + s.name)
162		}
163	})
164	v := *s.value.Load()
165	if v.bisect != nil && !v.bisect.Stack(&stderr) {
166		return ""
167	}
168	return v.text
169}
170
171// lookup returns the unique *setting value for the given name.
172func lookup(name string) *setting {
173	if v, ok := cache.Load(name); ok {
174		return v.(*setting)
175	}
176	s := new(setting)
177	s.info = godebugs.Lookup(name)
178	s.value.Store(&empty)
179	if v, loaded := cache.LoadOrStore(name, s); loaded {
180		// Lost race: someone else created it. Use theirs.
181		return v.(*setting)
182	}
183
184	return s
185}
186
187// setUpdate is provided by package runtime.
188// It calls update(def, env), where def is the default GODEBUG setting
189// and env is the current value of the $GODEBUG environment variable.
190// After that first call, the runtime calls update(def, env)
191// again each time the environment variable changes
192// (due to use of os.Setenv, for example).
193//
194//go:linkname setUpdate
195func setUpdate(update func(string, string))
196
197// registerMetric is provided by package runtime.
198// It forwards registrations to runtime/metrics.
199//
200//go:linkname registerMetric
201func registerMetric(name string, read func() uint64)
202
203// setNewIncNonDefault is provided by package runtime.
204// The runtime can do
205//
206//	inc := newNonDefaultInc(name)
207//
208// instead of
209//
210//	inc := godebug.New(name).IncNonDefault
211//
212// since it cannot import godebug.
213//
214//go:linkname setNewIncNonDefault
215func setNewIncNonDefault(newIncNonDefault func(string) func())
216
217func init() {
218	setUpdate(update)
219	setNewIncNonDefault(newIncNonDefault)
220}
221
222func newIncNonDefault(name string) func() {
223	s := New(name)
224	s.Value()
225	return s.IncNonDefault
226}
227
228var updateMu sync.Mutex
229
230// update records an updated GODEBUG setting.
231// def is the default GODEBUG setting for the running binary,
232// and env is the current value of the $GODEBUG environment variable.
233func update(def, env string) {
234	updateMu.Lock()
235	defer updateMu.Unlock()
236
237	// Update all the cached values, creating new ones as needed.
238	// We parse the environment variable first, so that any settings it has
239	// are already locked in place (did[name] = true) before we consider
240	// the defaults.
241	did := make(map[string]bool)
242	parse(did, env)
243	parse(did, def)
244
245	// Clear any cached values that are no longer present.
246	cache.Range(func(name, s any) bool {
247		if !did[name.(string)] {
248			s.(*setting).value.Store(&empty)
249		}
250		return true
251	})
252}
253
254// parse parses the GODEBUG setting string s,
255// which has the form k=v,k2=v2,k3=v3.
256// Later settings override earlier ones.
257// Parse only updates settings k=v for which did[k] = false.
258// It also sets did[k] = true for settings that it updates.
259// Each value v can also have the form v#pattern,
260// in which case the GODEBUG is only enabled for call stacks
261// matching pattern, for use with golang.org/x/tools/cmd/bisect.
262func parse(did map[string]bool, s string) {
263	// Scan the string backward so that later settings are used
264	// and earlier settings are ignored.
265	// Note that a forward scan would cause cached values
266	// to temporarily use the ignored value before being
267	// updated to the "correct" one.
268	end := len(s)
269	eq := -1
270	for i := end - 1; i >= -1; i-- {
271		if i == -1 || s[i] == ',' {
272			if eq >= 0 {
273				name, arg := s[i+1:eq], s[eq+1:end]
274				if !did[name] {
275					did[name] = true
276					v := &value{text: arg}
277					for j := 0; j < len(arg); j++ {
278						if arg[j] == '#' {
279							v.text = arg[:j]
280							v.bisect, _ = bisect.New(arg[j+1:])
281							break
282						}
283					}
284					lookup(name).value.Store(v)
285				}
286			}
287			eq = -1
288			end = i
289		} else if s[i] == '=' {
290			eq = i
291		}
292	}
293}
294
295type runtimeStderr struct{}
296
297var stderr runtimeStderr
298
299func (*runtimeStderr) Write(b []byte) (int, error) {
300	if len(b) > 0 {
301		write(2, unsafe.Pointer(&b[0]), int32(len(b)))
302	}
303	return len(b), nil
304}
305
306// Since we cannot import os or syscall, use the runtime's write function
307// to print to standard error.
308//
309//go:linkname write runtime.write
310func write(fd uintptr, p unsafe.Pointer, n int32) int32
311