Source file src/runtime/error.go

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

View as plain text