1// Copyright 2010 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 5package runtime 6 7import ( 8 "internal/abi" 9 "internal/bytealg" 10) 11 12// The Error interface identifies a run time error. 13type Error interface { 14 error 15 16 // RuntimeError is a no-op function but 17 // serves to distinguish types that are run time 18 // errors from ordinary errors: a type is a 19 // run time error if it has a RuntimeError method. 20 RuntimeError() 21} 22 23// A TypeAssertionError explains a failed type assertion. 24type TypeAssertionError struct { 25 _interface *_type 26 concrete *_type 27 asserted *_type 28 missingMethod string // one method needed by Interface, missing from Concrete 29} 30 31func (*TypeAssertionError) RuntimeError() {} 32 33func (e *TypeAssertionError) Error() string { 34 inter := "interface" 35 if e._interface != nil { 36 inter = toRType(e._interface).string() 37 } 38 as := toRType(e.asserted).string() 39 if e.concrete == nil { 40 return "interface conversion: " + inter + " is nil, not " + as 41 } 42 cs := toRType(e.concrete).string() 43 if e.missingMethod == "" { 44 msg := "interface conversion: " + inter + " is " + cs + ", not " + as 45 if cs == as { 46 // provide slightly clearer error message 47 if toRType(e.concrete).pkgpath() != toRType(e.asserted).pkgpath() { 48 msg += " (types from different packages)" 49 } else { 50 msg += " (types from different scopes)" 51 } 52 } 53 return msg 54 } 55 return "interface conversion: " + cs + " is not " + as + 56 ": missing method " + e.missingMethod 57} 58 59// itoa converts val to a decimal representation. The result is 60// written somewhere within buf and the location of the result is returned. 61// buf must be at least 20 bytes. 62// 63//go:nosplit 64func itoa(buf []byte, val uint64) []byte { 65 i := len(buf) - 1 66 for val >= 10 { 67 buf[i] = byte(val%10 + '0') 68 i-- 69 val /= 10 70 } 71 buf[i] = byte(val + '0') 72 return buf[i:] 73} 74 75// An errorString represents a runtime error described by a single string. 76type errorString string 77 78func (e errorString) RuntimeError() {} 79 80func (e errorString) Error() string { 81 return "runtime error: " + string(e) 82} 83 84type errorAddressString struct { 85 msg string // error message 86 addr uintptr // memory address where the error occurred 87} 88 89func (e errorAddressString) RuntimeError() {} 90 91func (e errorAddressString) Error() string { 92 return "runtime error: " + e.msg 93} 94 95// Addr returns the memory address where a fault occurred. 96// The address provided is best-effort. 97// The veracity of the result may depend on the platform. 98// Errors providing this method will only be returned as 99// a result of using [runtime/debug.SetPanicOnFault]. 100func (e errorAddressString) Addr() uintptr { 101 return e.addr 102} 103 104// plainError represents a runtime error described a string without 105// the prefix "runtime error: " after invoking errorString.Error(). 106// See Issue #14965. 107type plainError string 108 109func (e plainError) RuntimeError() {} 110 111func (e plainError) Error() string { 112 return string(e) 113} 114 115// A boundsError represents an indexing or slicing operation gone wrong. 116type boundsError struct { 117 x int64 118 y int 119 // Values in an index or slice expression can be signed or unsigned. 120 // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1. 121 // Instead, we keep track of whether x should be interpreted as signed or unsigned. 122 // y is known to be nonnegative and to fit in an int. 123 signed bool 124 code boundsErrorCode 125} 126 127type boundsErrorCode uint8 128 129const ( 130 boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed 131 132 boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed 133 boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed 134 boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen) 135 136 boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed 137 boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed 138 boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen) 139 boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen) 140 141 boundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed 142 // Note: in the above, len(s) and cap(s) are stored in y 143) 144 145// boundsErrorFmts provide error text for various out-of-bounds panics. 146// Note: if you change these strings, you should adjust the size of the buffer 147// in boundsError.Error below as well. 148var boundsErrorFmts = [...]string{ 149 boundsIndex: "index out of range [%x] with length %y", 150 boundsSliceAlen: "slice bounds out of range [:%x] with length %y", 151 boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y", 152 boundsSliceB: "slice bounds out of range [%x:%y]", 153 boundsSlice3Alen: "slice bounds out of range [::%x] with length %y", 154 boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y", 155 boundsSlice3B: "slice bounds out of range [:%x:%y]", 156 boundsSlice3C: "slice bounds out of range [%x:%y:]", 157 boundsConvert: "cannot convert slice with length %y to array or pointer to array with length %x", 158} 159 160// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y. 161var boundsNegErrorFmts = [...]string{ 162 boundsIndex: "index out of range [%x]", 163 boundsSliceAlen: "slice bounds out of range [:%x]", 164 boundsSliceAcap: "slice bounds out of range [:%x]", 165 boundsSliceB: "slice bounds out of range [%x:]", 166 boundsSlice3Alen: "slice bounds out of range [::%x]", 167 boundsSlice3Acap: "slice bounds out of range [::%x]", 168 boundsSlice3B: "slice bounds out of range [:%x:]", 169 boundsSlice3C: "slice bounds out of range [%x::]", 170} 171 172func (e boundsError) RuntimeError() {} 173 174func appendIntStr(b []byte, v int64, signed bool) []byte { 175 if signed && v < 0 { 176 b = append(b, '-') 177 v = -v 178 } 179 var buf [20]byte 180 b = append(b, itoa(buf[:], uint64(v))...) 181 return b 182} 183 184func (e boundsError) Error() string { 185 fmt := boundsErrorFmts[e.code] 186 if e.signed && e.x < 0 { 187 fmt = boundsNegErrorFmts[e.code] 188 } 189 // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y" 190 // x can be at most 20 characters. y can be at most 19. 191 b := make([]byte, 0, 100) 192 b = append(b, "runtime error: "...) 193 for i := 0; i < len(fmt); i++ { 194 c := fmt[i] 195 if c != '%' { 196 b = append(b, c) 197 continue 198 } 199 i++ 200 switch fmt[i] { 201 case 'x': 202 b = appendIntStr(b, e.x, e.signed) 203 case 'y': 204 b = appendIntStr(b, int64(e.y), true) 205 } 206 } 207 return string(b) 208} 209 210type stringer interface { 211 String() string 212} 213 214// printpanicval prints an argument passed to panic. 215// If panic is called with a value that has a String or Error method, 216// it has already been converted into a string by preprintpanics. 217// 218// To ensure that the traceback can be unambiguously parsed even when 219// the panic value contains "\ngoroutine" and other stack-like 220// strings, newlines in the string representation of v are replaced by 221// "\n\t". 222func printpanicval(v any) { 223 switch v := v.(type) { 224 case nil: 225 print("nil") 226 case bool: 227 print(v) 228 case int: 229 print(v) 230 case int8: 231 print(v) 232 case int16: 233 print(v) 234 case int32: 235 print(v) 236 case int64: 237 print(v) 238 case uint: 239 print(v) 240 case uint8: 241 print(v) 242 case uint16: 243 print(v) 244 case uint32: 245 print(v) 246 case uint64: 247 print(v) 248 case uintptr: 249 print(v) 250 case float32: 251 print(v) 252 case float64: 253 print(v) 254 case complex64: 255 print(v) 256 case complex128: 257 print(v) 258 case string: 259 printindented(v) 260 default: 261 printanycustomtype(v) 262 } 263} 264 265// Invariant: each newline in the string representation is followed by a tab. 266func printanycustomtype(i any) { 267 eface := efaceOf(&i) 268 typestring := toRType(eface._type).string() 269 270 switch eface._type.Kind_ { 271 case abi.String: 272 print(typestring, `("`) 273 printindented(*(*string)(eface.data)) 274 print(`")`) 275 case abi.Bool: 276 print(typestring, "(", *(*bool)(eface.data), ")") 277 case abi.Int: 278 print(typestring, "(", *(*int)(eface.data), ")") 279 case abi.Int8: 280 print(typestring, "(", *(*int8)(eface.data), ")") 281 case abi.Int16: 282 print(typestring, "(", *(*int16)(eface.data), ")") 283 case abi.Int32: 284 print(typestring, "(", *(*int32)(eface.data), ")") 285 case abi.Int64: 286 print(typestring, "(", *(*int64)(eface.data), ")") 287 case abi.Uint: 288 print(typestring, "(", *(*uint)(eface.data), ")") 289 case abi.Uint8: 290 print(typestring, "(", *(*uint8)(eface.data), ")") 291 case abi.Uint16: 292 print(typestring, "(", *(*uint16)(eface.data), ")") 293 case abi.Uint32: 294 print(typestring, "(", *(*uint32)(eface.data), ")") 295 case abi.Uint64: 296 print(typestring, "(", *(*uint64)(eface.data), ")") 297 case abi.Uintptr: 298 print(typestring, "(", *(*uintptr)(eface.data), ")") 299 case abi.Float32: 300 print(typestring, "(", *(*float32)(eface.data), ")") 301 case abi.Float64: 302 print(typestring, "(", *(*float64)(eface.data), ")") 303 case abi.Complex64: 304 print(typestring, *(*complex64)(eface.data)) 305 case abi.Complex128: 306 print(typestring, *(*complex128)(eface.data)) 307 default: 308 print("(", typestring, ") ", eface.data) 309 } 310} 311 312// printindented prints s, replacing "\n" with "\n\t". 313func printindented(s string) { 314 for { 315 i := bytealg.IndexByteString(s, '\n') 316 if i < 0 { 317 break 318 } 319 i += len("\n") 320 print(s[:i]) 321 print("\t") 322 s = s[i:] 323 } 324 print(s) 325} 326 327// panicwrap generates a panic for a call to a wrapped value method 328// with a nil pointer receiver. 329// 330// It is called from the generated wrapper code. 331func panicwrap() { 332 pc := getcallerpc() 333 name := funcNameForPrint(funcname(findfunc(pc))) 334 // name is something like "main.(*T).F". 335 // We want to extract pkg ("main"), typ ("T"), and meth ("F"). 336 // Do it by finding the parens. 337 i := bytealg.IndexByteString(name, '(') 338 if i < 0 { 339 throw("panicwrap: no ( in " + name) 340 } 341 pkg := name[:i-1] 342 if i+2 >= len(name) || name[i-1:i+2] != ".(*" { 343 throw("panicwrap: unexpected string after package name: " + name) 344 } 345 name = name[i+2:] 346 i = bytealg.IndexByteString(name, ')') 347 if i < 0 { 348 throw("panicwrap: no ) in " + name) 349 } 350 if i+2 >= len(name) || name[i:i+2] != ")." { 351 throw("panicwrap: unexpected string after type name: " + name) 352 } 353 typ := name[:i] 354 meth := name[i+2:] 355 panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")) 356} 357