Source file
src/runtime/traceback_test.go
1
2
3
4
5 package runtime_test
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/abi"
11 "internal/asan"
12 "internal/msan"
13 "internal/race"
14 "internal/testenv"
15 "regexp"
16 "runtime"
17 "runtime/debug"
18 "strconv"
19 "strings"
20 "sync"
21 "testing"
22 _ "unsafe"
23 )
24
25
26 func TestTracebackInlined(t *testing.T) {
27 testenv.SkipIfOptimizationOff(t)
28 check := func(t *testing.T, r *ttiResult, funcs ...string) {
29 t.Helper()
30
31
32 frames := parseTraceback1(t, r.printed).frames
33 t.Log(r.printed)
34
35 for len(frames) > 0 && frames[0].funcName != "runtime_test.ttiLeaf" {
36 frames = frames[1:]
37 }
38 if len(frames) == 0 {
39 t.Errorf("missing runtime_test.ttiLeaf")
40 return
41 }
42 frames = frames[1:]
43
44 for i, want := range funcs {
45 got := "<end>"
46 if i < len(frames) {
47 got = frames[i].funcName
48 if strings.HasSuffix(want, ")") {
49 got += "(" + frames[i].args + ")"
50 }
51 }
52 if got != want {
53 t.Errorf("got %s, want %s", got, want)
54 return
55 }
56 }
57 }
58
59 t.Run("simple", func(t *testing.T) {
60
61 r := ttiSimple1()
62 check(t, r, "runtime_test.ttiSimple3(...)", "runtime_test.ttiSimple2(...)", "runtime_test.ttiSimple1()")
63 })
64
65 t.Run("sigpanic", func(t *testing.T) {
66
67 r := ttiSigpanic1()
68 check(t, r, "runtime_test.ttiSigpanic1.func1()", "panic", "runtime_test.ttiSigpanic3(...)", "runtime_test.ttiSigpanic2(...)", "runtime_test.ttiSigpanic1()")
69 })
70
71 t.Run("wrapper", func(t *testing.T) {
72
73 r := ttiWrapper1()
74 check(t, r, "runtime_test.ttiWrapper.m1(...)", "runtime_test.ttiWrapper1()")
75 })
76
77 t.Run("excluded", func(t *testing.T) {
78
79
80 r := ttiExcluded1()
81 check(t, r, "runtime_test.ttiExcluded3(...)", "runtime_test.ttiExcluded1()")
82 })
83 }
84
85 type ttiResult struct {
86 printed string
87 }
88
89
90 func ttiLeaf() *ttiResult {
91
92 printed := string(debug.Stack())
93 return &ttiResult{printed}
94 }
95
96
97 func ttiSimple1() *ttiResult {
98 return ttiSimple2()
99 }
100 func ttiSimple2() *ttiResult {
101 return ttiSimple3()
102 }
103 func ttiSimple3() *ttiResult {
104 return ttiLeaf()
105 }
106
107
108 func ttiSigpanic1() (res *ttiResult) {
109 defer func() {
110 res = ttiLeaf()
111 recover()
112 }()
113 ttiSigpanic2()
114
115
116
117 if alwaysTrue {
118 panic("did not panic")
119 }
120 return nil
121 }
122 func ttiSigpanic2() {
123 ttiSigpanic3()
124 }
125 func ttiSigpanic3() {
126 var p *int
127 *p = 3
128 }
129
130 var alwaysTrue = true
131
132
133 func ttiWrapper1() *ttiResult {
134 var w ttiWrapper
135 m := (*ttiWrapper).m1
136 return m(&w)
137 }
138
139 type ttiWrapper struct{}
140
141 func (w ttiWrapper) m1() *ttiResult {
142 return ttiLeaf()
143 }
144
145
146 func ttiExcluded1() *ttiResult {
147 return ttiExcluded2()
148 }
149
150
151
152
153
154
155
156
157 func ttiExcluded2() *ttiResult {
158 return ttiExcluded3()
159 }
160 func ttiExcluded3() *ttiResult {
161 return ttiLeaf()
162 }
163
164 var testTracebackArgsBuf [1000]byte
165
166 func TestTracebackElision(t *testing.T) {
167
168
169
170
171 for _, elided := range []int{0, 1, 10} {
172 t.Run(fmt.Sprintf("elided=%d", elided), func(t *testing.T) {
173 n := elided + runtime.TracebackInnerFrames + runtime.TracebackOuterFrames
174
175
176 stackChan := make(chan string)
177 go tteStack(n, stackChan)
178 stack := <-stackChan
179 tb := parseTraceback1(t, stack)
180
181
182 i := 0
183 for i < n {
184 if len(tb.frames) == 0 {
185 t.Errorf("traceback ended early")
186 break
187 }
188 fr := tb.frames[0]
189 if i == runtime.TracebackInnerFrames && elided > 0 {
190
191 if fr.elided != elided {
192 t.Errorf("want %d frames elided", elided)
193 break
194 }
195 i += fr.elided
196 } else {
197 want := fmt.Sprintf("runtime_test.tte%d", (i+1)%5)
198 if i == 0 {
199 want = "runtime/debug.Stack"
200 } else if i == n-1 {
201 want = "runtime_test.tteStack"
202 }
203 if fr.funcName != want {
204 t.Errorf("want %s, got %s", want, fr.funcName)
205 break
206 }
207 i++
208 }
209 tb.frames = tb.frames[1:]
210 }
211 if !t.Failed() && len(tb.frames) > 0 {
212 t.Errorf("got %d more frames than expected", len(tb.frames))
213 }
214 if t.Failed() {
215 t.Logf("traceback diverged at frame %d", i)
216 off := len(stack)
217 if len(tb.frames) > 0 {
218 off = tb.frames[0].off
219 }
220 t.Logf("traceback before error:\n%s", stack[:off])
221 t.Logf("traceback after error:\n%s", stack[off:])
222 }
223 })
224 }
225 }
226
227
228
229
230 func tteStack(n int, stack chan<- string) {
231 n--
232
233
234 switch n % 5 {
235 case 0:
236 stack <- tte0(n)
237 case 1:
238 stack <- tte1(n)
239 case 2:
240 stack <- tte2(n)
241 case 3:
242 stack <- tte3(n)
243 case 4:
244 stack <- tte4(n)
245 default:
246 panic("unreachable")
247 }
248 }
249 func tte0(n int) string {
250 return tte4(n - 1)
251 }
252 func tte1(n int) string {
253 return tte0(n - 1)
254 }
255 func tte2(n int) string {
256
257
258 if n < 2 {
259 panic("bad n")
260 }
261 if n == 2 {
262 return string(debug.Stack())
263 }
264 return tte1(n - 1)
265 }
266 func tte3(n int) string {
267 return tte2(n - 1)
268 }
269 func tte4(n int) string {
270 return tte3(n - 1)
271 }
272
273 func TestTracebackArgs(t *testing.T) {
274 if *flagQuick {
275 t.Skip("-quick")
276 }
277 optimized := !testenv.OptimizationOff()
278 abiSel := func(x, y string) string {
279
280
281 if optimized && abi.IntArgRegs > 0 {
282 return x
283 }
284 return y
285 }
286
287 tests := []struct {
288 fn func() int
289 expect string
290 }{
291
292 {
293 func() int { return testTracebackArgs1(1, 2, 3, 4, 5) },
294 "testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5)",
295 },
296
297 {
298 func() int {
299 return testTracebackArgs2(false, struct {
300 a, b, c int
301 x [2]int
302 }{1, 2, 3, [2]int{4, 5}}, [0]int{}, [3]byte{6, 7, 8})
303 },
304 "testTracebackArgs2(0x0, {0x1, 0x2, 0x3, {0x4, 0x5}}, {}, {0x6, 0x7, 0x8})",
305 },
306 {
307 func() int { return testTracebackArgs3([3]byte{1, 2, 3}, 4, 5, 6, [3]byte{7, 8, 9}) },
308 "testTracebackArgs3({0x1, 0x2, 0x3}, 0x4, 0x5, 0x6, {0x7, 0x8, 0x9})",
309 },
310
311 {
312 func() int { return testTracebackArgs4(false, [1][1][1][1][1][1][1][1][1][1]int{}) },
313 "testTracebackArgs4(0x0, {{{{{...}}}}})",
314 },
315
316 {
317 func() int {
318 z := [0]int{}
319 return testTracebackArgs5(false, struct {
320 x int
321 y [0]int
322 z [2][0]int
323 }{1, z, [2][0]int{}}, z, z, z, z, z, z, z, z, z, z, z, z)
324 },
325 "testTracebackArgs5(0x0, {0x1, {}, {{}, {}}}, {}, {}, {}, {}, {}, ...)",
326 },
327
328
329
330 {
331 func() int { return testTracebackArgs6a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) },
332 "testTracebackArgs6a(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa)",
333 },
334
335 {
336 func() int { return testTracebackArgs6b(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) },
337 "testTracebackArgs6b(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)",
338 },
339
340 {
341 func() int { return testTracebackArgs7a([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) },
342 "testTracebackArgs7a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa})",
343 },
344
345 {
346 func() int { return testTracebackArgs7b([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) },
347 "testTracebackArgs7b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...})",
348 },
349
350 {
351 func() int { return testTracebackArgs7c([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11) },
352 "testTracebackArgs7c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}, ...)",
353 },
354
355 {
356 func() int { return testTracebackArgs7d([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 12) },
357 "testTracebackArgs7d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...}, ...)",
358 },
359
360 {
361 func() int { return testTracebackArgs8a(testArgsType8a{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}}) },
362 "testTracebackArgs8a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}})",
363 },
364
365 {
366 func() int { return testTracebackArgs8b(testArgsType8b{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}}) },
367 "testTracebackArgs8b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}})",
368 },
369
370 {
371 func() int { return testTracebackArgs8c(testArgsType8c{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}, 11}) },
372 "testTracebackArgs8c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}, ...})",
373 },
374
375 {
376 func() int { return testTracebackArgs8d(testArgsType8d{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}, 12}) },
377 "testTracebackArgs8d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}, ...})",
378 },
379
380
381
382
383 {
384 func() int {
385 poisonStack()
386 return testTracebackArgs9(1, 2, 3, 4, [2]int{5, 6}, 7)
387 },
388 abiSel(
389 "testTracebackArgs9(0x1, 0xffffffff?, 0x3, 0xff?, {0x5, 0x6}, 0x7)",
390 "testTracebackArgs9(0x1, 0x2, 0x3, 0x4, {0x5, 0x6}, 0x7)"),
391 },
392
393
394 {
395 func() int {
396 poisonStack()
397 return testTracebackArgs10(1, 2, 3, 4, 5)
398 },
399 abiSel(
400 "testTracebackArgs10(0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?, 0xffffffff?)",
401 "testTracebackArgs10(0x1, 0x2, 0x3, 0x4, 0x5)"),
402 },
403
404
405 {
406 func() int {
407 poisonStack()
408 return testTracebackArgs11a(1, 2, 3)
409 },
410 abiSel(
411 "testTracebackArgs11a(0xffffffff?, 0xffffffff?, 0xffffffff?)",
412 "testTracebackArgs11a(0x1, 0x2, 0x3)"),
413 },
414
415
416 {
417 func() int {
418 poisonStack()
419 return testTracebackArgs11b(1, 2, 3, 4)
420 },
421 abiSel(
422 "testTracebackArgs11b(0xffffffff?, 0xffffffff?, 0x3?, 0x4)",
423 "testTracebackArgs11b(0x1, 0x2, 0x3, 0x4)"),
424 },
425
426
427
428 {
429 func() int {
430 poisonStack()
431 return testTracebackArgsSlice(testTracebackArgsSliceBackingStore[:])
432 },
433
434 fmt.Sprintf("testTracebackArgsSlice({%p, 0x2, ", &testTracebackArgsSliceBackingStore[0]),
435 },
436 }
437 for _, test := range tests {
438 n := test.fn()
439 got := testTracebackArgsBuf[:n]
440 if !bytes.Contains(got, []byte(test.expect)) {
441 t.Errorf("traceback does not contain expected string: want %q, got\n%s", test.expect, got)
442 }
443 }
444 }
445
446
447 func testTracebackArgs1(a, b, c, d, e int) int {
448 n := runtime.Stack(testTracebackArgsBuf[:], false)
449 if a < 0 {
450
451 return a + b + c + d + e
452 }
453 return n
454 }
455
456
457 func testTracebackArgs2(a bool, b struct {
458 a, b, c int
459 x [2]int
460 }, _ [0]int, d [3]byte) int {
461 n := runtime.Stack(testTracebackArgsBuf[:], false)
462 if a {
463
464 return b.a + b.b + b.c + b.x[0] + b.x[1] + int(d[0]) + int(d[1]) + int(d[2])
465 }
466 return n
467 }
468
469
470
471 func testTracebackArgs3(x [3]byte, a, b, c int, y [3]byte) int {
472 n := runtime.Stack(testTracebackArgsBuf[:], false)
473 if a < 0 {
474
475 return int(x[0]) + int(x[1]) + int(x[2]) + a + b + c + int(y[0]) + int(y[1]) + int(y[2])
476 }
477 return n
478 }
479
480
481 func testTracebackArgs4(a bool, x [1][1][1][1][1][1][1][1][1][1]int) int {
482 n := runtime.Stack(testTracebackArgsBuf[:], false)
483 if a {
484 panic(x)
485 }
486 return n
487 }
488
489
490 func testTracebackArgs5(a bool, x struct {
491 x int
492 y [0]int
493 z [2][0]int
494 }, _, _, _, _, _, _, _, _, _, _, _, _ [0]int) int {
495 n := runtime.Stack(testTracebackArgsBuf[:], false)
496 if a {
497 panic(x)
498 }
499 return n
500 }
501
502
503 func testTracebackArgs6a(a, b, c, d, e, f, g, h, i, j int) int {
504 n := runtime.Stack(testTracebackArgsBuf[:], false)
505 if a < 0 {
506
507 return a + b + c + d + e + f + g + h + i + j
508 }
509 return n
510 }
511
512
513 func testTracebackArgs6b(a, b, c, d, e, f, g, h, i, j, k int) int {
514 n := runtime.Stack(testTracebackArgsBuf[:], false)
515 if a < 0 {
516
517 return a + b + c + d + e + f + g + h + i + j + k
518 }
519 return n
520 }
521
522
523 func testTracebackArgs7a(a [10]int) int {
524 n := runtime.Stack(testTracebackArgsBuf[:], false)
525 if a[0] < 0 {
526
527 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
528 }
529 return n
530 }
531
532
533 func testTracebackArgs7b(a [11]int) int {
534 n := runtime.Stack(testTracebackArgsBuf[:], false)
535 if a[0] < 0 {
536
537 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10]
538 }
539 return n
540 }
541
542
543 func testTracebackArgs7c(a [10]int, b int) int {
544 n := runtime.Stack(testTracebackArgsBuf[:], false)
545 if a[0] < 0 {
546
547 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + b
548 }
549 return n
550 }
551
552
553 func testTracebackArgs7d(a [11]int, b int) int {
554 n := runtime.Stack(testTracebackArgsBuf[:], false)
555 if a[0] < 0 {
556
557 return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + b
558 }
559 return n
560 }
561
562 type testArgsType8a struct {
563 a, b, c, d, e, f, g, h int
564 i [2]int
565 }
566 type testArgsType8b struct {
567 a, b, c, d, e, f, g, h int
568 i [3]int
569 }
570 type testArgsType8c struct {
571 a, b, c, d, e, f, g, h int
572 i [2]int
573 j int
574 }
575 type testArgsType8d struct {
576 a, b, c, d, e, f, g, h int
577 i [3]int
578 j int
579 }
580
581
582 func testTracebackArgs8a(a testArgsType8a) int {
583 n := runtime.Stack(testTracebackArgsBuf[:], false)
584 if a.a < 0 {
585
586 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1]
587 }
588 return n
589 }
590
591
592 func testTracebackArgs8b(a testArgsType8b) int {
593 n := runtime.Stack(testTracebackArgsBuf[:], false)
594 if a.a < 0 {
595
596 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2]
597 }
598 return n
599 }
600
601
602 func testTracebackArgs8c(a testArgsType8c) int {
603 n := runtime.Stack(testTracebackArgsBuf[:], false)
604 if a.a < 0 {
605
606 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.j
607 }
608 return n
609 }
610
611
612 func testTracebackArgs8d(a testArgsType8d) int {
613 n := runtime.Stack(testTracebackArgsBuf[:], false)
614 if a.a < 0 {
615
616 return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2] + a.j
617 }
618 return n
619 }
620
621
622
623
624
625 func testTracebackArgs9(a int64, b int32, c int16, d int8, x [2]int, y int) int {
626 if a < 0 {
627 println(&y)
628 }
629 n := runtime.Stack(testTracebackArgsBuf[:], false)
630 if a < 0 {
631
632 return int(a) + int(c)
633 }
634 return n
635 }
636
637
638
639
640
641 func testTracebackArgs10(a, b, c, d, e int32) int {
642
643 return runtime.Stack(testTracebackArgsBuf[:], false)
644 }
645
646
647
648
649
650
651
652 func testTracebackArgs11a(a, b, c int32) int {
653 if a < 0 {
654 println(a, b, c)
655 }
656 if b < 0 {
657 return int(a + b + c)
658 }
659 return runtime.Stack(testTracebackArgsBuf[:], false)
660 }
661
662
663
664
665
666
667
668 func testTracebackArgs11b(a, b, c, d int32) int {
669 var x int32
670 if a < 0 {
671 print()
672 x = b
673 } else {
674 print()
675 x = c
676 }
677 if d < 0 {
678 return int(x + d)
679 }
680 return runtime.Stack(testTracebackArgsBuf[:], false)
681 }
682
683
684
685
686
687
688
689 func testTracebackArgsSlice(a []int) int {
690 n := runtime.Stack(testTracebackArgsBuf[:], false)
691 return a[1] + n
692 }
693
694 var testTracebackArgsSliceBackingStore [2]int
695
696
697
698
699 func poisonStack() [20]int {
700 return [20]int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
701 }
702
703 func TestTracebackParentChildGoroutines(t *testing.T) {
704 parent := fmt.Sprintf("goroutine %d", runtime.Goid())
705 var wg sync.WaitGroup
706 wg.Add(1)
707 go func() {
708 defer wg.Done()
709 buf := make([]byte, 1<<10)
710
711
712
713
714 stack := string(buf[:runtime.Stack(buf, false)])
715 child := fmt.Sprintf("goroutine %d", runtime.Goid())
716 if !strings.Contains(stack, parent) || !strings.Contains(stack, child) {
717 t.Errorf("did not see parent (%s) and child (%s) IDs in stack, got %s", parent, child, stack)
718 }
719 }()
720 wg.Wait()
721 }
722
723 type traceback struct {
724 frames []*tbFrame
725 createdBy *tbFrame
726 }
727
728 type tbFrame struct {
729 funcName string
730 args string
731 inlined bool
732
733
734
735 elided int
736
737 off int
738 }
739
740
741
742 func parseTraceback(t *testing.T, tb string) []*traceback {
743
744
745 off := 0
746 lineNo := 0
747 fatal := func(f string, args ...any) {
748 msg := fmt.Sprintf(f, args...)
749 t.Fatalf("%s (line %d):\n%s", msg, lineNo, tb)
750 }
751 parseFrame := func(funcName, args string) *tbFrame {
752
753 if !strings.HasPrefix(tb, "\t") {
754 fatal("missing source line")
755 }
756 _, tb, _ = strings.Cut(tb, "\n")
757 lineNo++
758 inlined := args == "..."
759 return &tbFrame{funcName: funcName, args: args, inlined: inlined, off: off}
760 }
761 var elidedRe = regexp.MustCompile(`^\.\.\.([0-9]+) frames elided\.\.\.$`)
762 var tbs []*traceback
763 var cur *traceback
764 tbLen := len(tb)
765 for len(tb) > 0 {
766 var line string
767 off = tbLen - len(tb)
768 line, tb, _ = strings.Cut(tb, "\n")
769 lineNo++
770 switch {
771 case strings.HasPrefix(line, "goroutine "):
772 cur = &traceback{}
773 tbs = append(tbs, cur)
774 case line == "":
775
776 cur = nil
777 case line[0] == '\t':
778 fatal("unexpected indent")
779 case strings.HasPrefix(line, "created by "):
780 funcName := line[len("created by "):]
781 cur.createdBy = parseFrame(funcName, "")
782 case strings.HasSuffix(line, ")"):
783 line = line[:len(line)-1]
784 funcName, args, found := strings.Cut(line, "(")
785 if !found {
786 fatal("missing (")
787 }
788 frame := parseFrame(funcName, args)
789 cur.frames = append(cur.frames, frame)
790 case elidedRe.MatchString(line):
791
792 nStr := elidedRe.FindStringSubmatch(line)
793 n, _ := strconv.Atoi(nStr[1])
794 frame := &tbFrame{elided: n}
795 cur.frames = append(cur.frames, frame)
796 }
797 }
798 return tbs
799 }
800
801
802
803 func parseTraceback1(t *testing.T, tb string) *traceback {
804 tbs := parseTraceback(t, tb)
805 if len(tbs) != 1 {
806 t.Fatalf("want 1 goroutine, got %d:\n%s", len(tbs), tb)
807 }
808 return tbs[0]
809 }
810
811
812 func testTracebackGenericFn[T any](buf []byte) int {
813 return runtime.Stack(buf[:], false)
814 }
815
816 func testTracebackGenericFnInlined[T any](buf []byte) int {
817 return runtime.Stack(buf[:], false)
818 }
819
820 type testTracebackGenericTyp[P any] struct{ x P }
821
822
823 func (t testTracebackGenericTyp[P]) M(buf []byte) int {
824 return runtime.Stack(buf[:], false)
825 }
826
827 func (t testTracebackGenericTyp[P]) Inlined(buf []byte) int {
828 return runtime.Stack(buf[:], false)
829 }
830
831 func TestTracebackGeneric(t *testing.T) {
832 if *flagQuick {
833 t.Skip("-quick")
834 }
835 var x testTracebackGenericTyp[int]
836 tests := []struct {
837 fn func([]byte) int
838 expect string
839 }{
840
841 {
842 testTracebackGenericFn[int],
843 "testTracebackGenericFn[...](",
844 },
845
846 {
847 func(buf []byte) int { return testTracebackGenericFnInlined[int](buf) },
848 "testTracebackGenericFnInlined[...](",
849 },
850
851 {
852 x.M,
853 "testTracebackGenericTyp[...].M(",
854 },
855
856 {
857 func(buf []byte) int { return x.Inlined(buf) },
858 "testTracebackGenericTyp[...].Inlined(",
859 },
860 }
861 var buf [1000]byte
862 for _, test := range tests {
863 n := test.fn(buf[:])
864 got := buf[:n]
865 if !bytes.Contains(got, []byte(test.expect)) {
866 t.Errorf("traceback does not contain expected string: want %q, got\n%s", test.expect, got)
867 }
868 if bytes.Contains(got, []byte("shape")) {
869 t.Errorf("traceback contains shape name: got\n%s", got)
870 }
871 }
872 }
873
874 func TestSetCgoTracebackNoCgo(t *testing.T) {
875 if asan.Enabled || msan.Enabled || race.Enabled {
876 t.Skip("skipped test: sanitizer builds use cgo")
877 }
878
879 output := runTestProg(t, "testprog", "SetCgoTracebackNoCgo")
880 want := "OK\n"
881 if output != want {
882 t.Fatalf("want %s, got %s\n", want, output)
883 }
884 }
885
View as plain text