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