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 "internal/bytealg" 8 9// The Error interface identifies a run time error. 10type Error interface { 11 error 12 13 // RuntimeError is a no-op function but 14 // serves to distinguish types that are run time 15 // errors from ordinary errors: a type is a 16 // run time error if it has a RuntimeError method. 17 RuntimeError() 18} 19 20// A TypeAssertionError explains a failed type assertion. 21type TypeAssertionError struct { 22 _interface *_type 23 concrete *_type 24 asserted *_type 25 missingMethod string // one method needed by Interface, missing from Concrete 26} 27 28func (*TypeAssertionError) RuntimeError() {} 29 30func (e *TypeAssertionError) Error() string { 31 inter := "interface" 32 if e._interface != nil { 33 inter = e._interface.string() 34 } 35 as := e.asserted.string() 36 if e.concrete == nil { 37 return "interface conversion: " + inter + " is nil, not " + as 38 } 39 cs := e.concrete.string() 40 if e.missingMethod == "" { 41 msg := "interface conversion: " + inter + " is " + cs + ", not " + as 42 if cs == as { 43 // provide slightly clearer error message 44 if e.concrete.pkgpath() != e.asserted.pkgpath() { 45 msg += " (types from different packages)" 46 } else { 47 msg += " (types from different scopes)" 48 } 49 } 50 return msg 51 } 52 return "interface conversion: " + cs + " is not " + as + 53 ": missing method " + e.missingMethod 54} 55 56//go:nosplit 57// itoa converts val to a decimal representation. The result is 58// written somewhere within buf and the location of the result is returned. 59// buf must be at least 20 bytes. 60func itoa(buf []byte, val uint64) []byte { 61 i := len(buf) - 1 62 for val >= 10 { 63 buf[i] = byte(val%10 + '0') 64 i-- 65 val /= 10 66 } 67 buf[i] = byte(val + '0') 68 return buf[i:] 69} 70 71// An errorString represents a runtime error described by a single string. 72type errorString string 73 74func (e errorString) RuntimeError() {} 75 76func (e errorString) Error() string { 77 return "runtime error: " + string(e) 78} 79 80// plainError represents a runtime error described a string without 81// the prefix "runtime error: " after invoking errorString.Error(). 82// See Issue #14965. 83type plainError string 84 85func (e plainError) RuntimeError() {} 86 87func (e plainError) Error() string { 88 return string(e) 89} 90 91// A boundsError represents an indexing or slicing operation gone wrong. 92type boundsError struct { 93 x int64 94 y int 95 // Values in an index or slice expression can be signed or unsigned. 96 // That means we'd need 65 bits to encode all possible indexes, from -2^63 to 2^64-1. 97 // Instead, we keep track of whether x should be interpreted as signed or unsigned. 98 // y is known to be nonnegative and to fit in an int. 99 signed bool 100 code boundsErrorCode 101} 102 103type boundsErrorCode uint8 104 105const ( 106 boundsIndex boundsErrorCode = iota // s[x], 0 <= x < len(s) failed 107 108 boundsSliceAlen // s[?:x], 0 <= x <= len(s) failed 109 boundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed 110 boundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen) 111 112 boundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed 113 boundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed 114 boundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen) 115 boundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen) 116 117 // Note: in the above, len(s) and cap(s) are stored in y 118) 119 120// boundsErrorFmts provide error text for various out-of-bounds panics. 121// Note: if you change these strings, you should adjust the size of the buffer 122// in boundsError.Error below as well. 123var boundsErrorFmts = [...]string{ 124 boundsIndex: "index out of range [%x] with length %y", 125 boundsSliceAlen: "slice bounds out of range [:%x] with length %y", 126 boundsSliceAcap: "slice bounds out of range [:%x] with capacity %y", 127 boundsSliceB: "slice bounds out of range [%x:%y]", 128 boundsSlice3Alen: "slice bounds out of range [::%x] with length %y", 129 boundsSlice3Acap: "slice bounds out of range [::%x] with capacity %y", 130 boundsSlice3B: "slice bounds out of range [:%x:%y]", 131 boundsSlice3C: "slice bounds out of range [%x:%y:]", 132} 133 134// boundsNegErrorFmts are overriding formats if x is negative. In this case there's no need to report y. 135var boundsNegErrorFmts = [...]string{ 136 boundsIndex: "index out of range [%x]", 137 boundsSliceAlen: "slice bounds out of range [:%x]", 138 boundsSliceAcap: "slice bounds out of range [:%x]", 139 boundsSliceB: "slice bounds out of range [%x:]", 140 boundsSlice3Alen: "slice bounds out of range [::%x]", 141 boundsSlice3Acap: "slice bounds out of range [::%x]", 142 boundsSlice3B: "slice bounds out of range [:%x:]", 143 boundsSlice3C: "slice bounds out of range [%x::]", 144} 145 146func (e boundsError) RuntimeError() {} 147 148func appendIntStr(b []byte, v int64, signed bool) []byte { 149 if signed && v < 0 { 150 b = append(b, '-') 151 v = -v 152 } 153 var buf [20]byte 154 b = append(b, itoa(buf[:], uint64(v))...) 155 return b 156} 157 158func (e boundsError) Error() string { 159 fmt := boundsErrorFmts[e.code] 160 if e.signed && e.x < 0 { 161 fmt = boundsNegErrorFmts[e.code] 162 } 163 // max message length is 99: "runtime error: slice bounds out of range [::%x] with capacity %y" 164 // x can be at most 20 characters. y can be at most 19. 165 b := make([]byte, 0, 100) 166 b = append(b, "runtime error: "...) 167 for i := 0; i < len(fmt); i++ { 168 c := fmt[i] 169 if c != '%' { 170 b = append(b, c) 171 continue 172 } 173 i++ 174 switch fmt[i] { 175 case 'x': 176 b = appendIntStr(b, e.x, e.signed) 177 case 'y': 178 b = appendIntStr(b, int64(e.y), true) 179 } 180 } 181 return string(b) 182} 183 184type stringer interface { 185 String() string 186} 187 188func typestring(x interface{}) string { 189 e := efaceOf(&x) 190 return e._type.string() 191} 192 193// printany prints an argument passed to panic. 194// If panic is called with a value that has a String or Error method, 195// it has already been converted into a string by preprintpanics. 196func printany(i interface{}) { 197 switch v := i.(type) { 198 case nil: 199 print("nil") 200 case bool: 201 print(v) 202 case int: 203 print(v) 204 case int8: 205 print(v) 206 case int16: 207 print(v) 208 case int32: 209 print(v) 210 case int64: 211 print(v) 212 case uint: 213 print(v) 214 case uint8: 215 print(v) 216 case uint16: 217 print(v) 218 case uint32: 219 print(v) 220 case uint64: 221 print(v) 222 case uintptr: 223 print(v) 224 case float32: 225 print(v) 226 case float64: 227 print(v) 228 case complex64: 229 print(v) 230 case complex128: 231 print(v) 232 case string: 233 print(v) 234 default: 235 print("(", typestring(i), ") ", i) 236 } 237} 238 239// panicwrap generates a panic for a call to a wrapped value method 240// with a nil pointer receiver. 241// 242// It is called from the generated wrapper code. 243func panicwrap() { 244 pc := getcallerpc() 245 name := funcname(findfunc(pc)) 246 // name is something like "main.(*T).F". 247 // We want to extract pkg ("main"), typ ("T"), and meth ("F"). 248 // Do it by finding the parens. 249 i := bytealg.IndexByteString(name, '(') 250 if i < 0 { 251 throw("panicwrap: no ( in " + name) 252 } 253 pkg := name[:i-1] 254 if i+2 >= len(name) || name[i-1:i+2] != ".(*" { 255 throw("panicwrap: unexpected string after package name: " + name) 256 } 257 name = name[i+2:] 258 i = bytealg.IndexByteString(name, ')') 259 if i < 0 { 260 throw("panicwrap: no ) in " + name) 261 } 262 if i+2 >= len(name) || name[i:i+2] != ")." { 263 throw("panicwrap: unexpected string after type name: " + name) 264 } 265 typ := name[:i] 266 meth := name[i+2:] 267 panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")) 268} 269