Source file src/internal/godebug/godebug.go
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 string 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 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. 93 func New(name string) *Setting { 94 return &Setting{name: name} 95 } 96 97 // Name returns the name of the setting. 98 func (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. 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 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. 121 func (s *Setting) IncNonDefault() { 122 s.nonDefaultOnce.Do(s.register) 123 s.nonDefault.Add(1) 124 } 125 126 func (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. 146 var cache sync.Map // name string -> value *atomic.Pointer[string] 147 148 var 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. 157 func (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. 172 func 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 195 func 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 201 func 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 215 func setNewIncNonDefault(newIncNonDefault func(string) func()) 216 217 func init() { 218 setUpdate(update) 219 setNewIncNonDefault(newIncNonDefault) 220 } 221 222 func newIncNonDefault(name string) func() { 223 s := New(name) 224 s.Value() 225 return s.IncNonDefault 226 } 227 228 var 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. 233 func 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. 262 func 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 295 type runtimeStderr struct{} 296 297 var stderr runtimeStderr 298 299 func (*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 310 func write(fd uintptr, p unsafe.Pointer, n int32) int32 311