github.com/goplus/igop@v0.25.0/runtime_test.go (about) 1 package igop_test 2 3 import ( 4 "testing" 5 6 "github.com/goplus/igop" 7 _ "github.com/goplus/igop/pkg/log" 8 ) 9 10 func TestFuncForPC(t *testing.T) { 11 src := `package main 12 13 import ( 14 "fmt" 15 "reflect" 16 "runtime" 17 ) 18 19 func test() { 20 println("hello") 21 } 22 23 func main() { 24 pc := reflect.ValueOf(test).Pointer() 25 fn := runtime.FuncForPC(pc) 26 if fn == nil { 27 panic("error runtime.FuncForPC") 28 } 29 if fn.Name() != "main.test" { 30 panic("error name: " + fn.Name()) 31 } 32 file, line := fn.FileLine(fn.Entry()) 33 if file != "main.go" { 34 panic("error file:" + file) 35 } 36 if line != 9 { 37 panic(fmt.Errorf("error line: %v", line)) 38 } 39 } 40 ` 41 _, err := igop.RunFile("main.go", src, nil, 0) 42 if err != nil { 43 t.Fatal(err) 44 } 45 } 46 47 func TestRuntimeCaller(t *testing.T) { 48 src := `package main 49 50 import ( 51 "fmt" 52 "path/filepath" 53 "runtime" 54 "strings" 55 ) 56 57 var t *struct { 58 c chan int 59 } 60 61 var c chan int 62 63 func f() { 64 select { 65 case <-t.c: // THIS IS LINE 18 66 break 67 case <-c: 68 break 69 } 70 } 71 72 func g() { 73 defer func() { 74 panic("error g1") 75 }() 76 defer func() { 77 panic("error g2") 78 }() 79 f() 80 panic("unreachable") 81 } 82 83 func main() { 84 defer func() { 85 recover() 86 var list []string 87 for i := 0; ; i++ { 88 pc, file, line, ok := runtime.Caller(i) 89 if !ok { 90 break 91 } 92 fn := runtime.FuncForPC(pc) 93 fnName := fn.Name() 94 if fnName == "runtime.gopanic" { 95 list = append(list, "runtime.gopanic") 96 } else if strings.HasPrefix(fnName, "main.") { 97 _, fname := filepath.Split(file) 98 list = append(list, fmt.Sprintf("%v %v:%v", fnName, fname, line)) 99 } 100 fmt.Println(pc, fnName, file, line) 101 } 102 if v := fmt.Sprint(list); v != infos { 103 panic(v) 104 } 105 }() 106 g() 107 } 108 109 var infos = "[main.main.func1 main.go:41 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.g.func2 main.go:30 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:59]" 110 ` 111 _, err := igop.RunFile("main.go", src, nil, 0) 112 if err != nil { 113 t.Fatal(err) 114 } 115 } 116 117 func TestRuntimeCallers1(t *testing.T) { 118 src := `package main 119 120 import ( 121 "fmt" 122 "path/filepath" 123 "runtime" 124 "strings" 125 ) 126 127 var t *struct { 128 c chan int 129 } 130 131 var c chan int 132 133 func f() { 134 select { 135 case <-t.c: // THIS IS LINE 18 136 break 137 case <-c: 138 break 139 } 140 } 141 142 func g() { 143 // defer func() { 144 // panic("error g1") 145 // }() 146 // defer func() { 147 // panic("error g2") 148 // }() 149 f() 150 panic("unreachable") 151 } 152 153 func main() { 154 defer func() { 155 recover() 156 rpc := make([]uintptr, 64) 157 runtime.Callers(0, rpc) 158 fs := runtime.CallersFrames(rpc) 159 var list []string 160 for { 161 f, more := fs.Next() 162 if f.Function == "runtime.gopanic" { 163 list = append(list, "runtime.gopanic") 164 } else if strings.HasPrefix(f.Function, "main.") { 165 _, fname := filepath.Split(f.File) 166 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 167 } 168 fmt.Println(f) 169 if !more { 170 break 171 } 172 } 173 if v := fmt.Sprint(list); v != infos { 174 panic(v) 175 } 176 }() 177 g() 178 } 179 180 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]" 181 ` 182 _, err := igop.RunFile("main.go", src, nil, 0) 183 if err != nil { 184 t.Fatal(err) 185 } 186 } 187 188 func TestRuntimeCallers2(t *testing.T) { 189 src := `package main 190 191 import ( 192 "fmt" 193 "path/filepath" 194 "runtime" 195 "strings" 196 ) 197 198 var t *struct { 199 c chan int 200 } 201 202 var c chan int 203 204 func f() { 205 select { 206 case <-t.c: // THIS IS LINE 18 207 break 208 case <-c: 209 break 210 } 211 } 212 213 func g() { 214 defer func() { 215 panic("error g1") 216 }() 217 // defer func() { 218 // panic("error g2") 219 // }() 220 f() 221 panic("unreachable") 222 } 223 224 func main() { 225 defer func() { 226 recover() 227 rpc := make([]uintptr, 64) 228 runtime.Callers(0, rpc) 229 fs := runtime.CallersFrames(rpc) 230 var list []string 231 for { 232 f, more := fs.Next() 233 if f.Function == "runtime.gopanic" { 234 list = append(list, "runtime.gopanic") 235 } else if strings.HasPrefix(f.Function, "main.") { 236 _, fname := filepath.Split(f.File) 237 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 238 } 239 fmt.Println(f) 240 if !more { 241 break 242 } 243 } 244 if v := fmt.Sprint(list); v != infos { 245 panic(v) 246 } 247 }() 248 g() 249 } 250 251 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]" 252 ` 253 _, err := igop.RunFile("main.go", src, nil, 0) 254 if err != nil { 255 t.Fatal(err) 256 } 257 } 258 259 func TestRuntimeCallers3(t *testing.T) { 260 src := `package main 261 262 import ( 263 "fmt" 264 "path/filepath" 265 "runtime" 266 "strings" 267 ) 268 269 var t *struct { 270 c chan int 271 } 272 273 var c chan int 274 275 func f() { 276 select { 277 case <-t.c: // THIS IS LINE 18 278 break 279 case <-c: 280 break 281 } 282 } 283 284 func g() { 285 defer func() { 286 panic("error g1") 287 }() 288 defer func() { 289 panic("error g2") 290 }() 291 f() 292 panic("unreachable") 293 } 294 295 func main() { 296 defer func() { 297 recover() 298 rpc := make([]uintptr, 64) 299 runtime.Callers(0, rpc) 300 fs := runtime.CallersFrames(rpc) 301 var list []string 302 for { 303 f, more := fs.Next() 304 if f.Function == "runtime.gopanic" { 305 list = append(list, "runtime.gopanic") 306 } else if strings.HasPrefix(f.Function, "main.") { 307 _, fname := filepath.Split(f.File) 308 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 309 } 310 fmt.Println(f) 311 if !more { 312 break 313 } 314 } 315 if v := fmt.Sprint(list); v != infos { 316 panic(v) 317 } 318 }() 319 g() 320 } 321 322 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.g.func2 main.go:30 runtime.gopanic main.f main.go:18 main.g main.go:32 main.main main.go:60]" 323 ` 324 _, err := igop.RunFile("main.go", src, nil, 0) 325 if err != nil { 326 t.Fatal(err) 327 } 328 } 329 330 func TestRuntimeCallers4(t *testing.T) { 331 src := `package main 332 333 import ( 334 "fmt" 335 "path/filepath" 336 "runtime" 337 "strings" 338 ) 339 340 var t *struct { 341 c chan int 342 } 343 344 var c chan int 345 346 func f() { 347 select { 348 case <-t.c: // THIS IS LINE 18 349 break 350 case <-c: 351 break 352 } 353 } 354 355 func g() { 356 defer func() { 357 // panic("error g1") 358 }() 359 defer func() { 360 // panic("error g2") 361 f() 362 }() 363 // f() 364 } 365 366 func main() { 367 defer func() { 368 recover() 369 rpc := make([]uintptr, 64) 370 runtime.Callers(0, rpc) 371 fs := runtime.CallersFrames(rpc) 372 var list []string 373 for { 374 f, more := fs.Next() 375 if f.Function == "runtime.gopanic" { 376 list = append(list, "runtime.gopanic") 377 } else if strings.HasPrefix(f.Function, "main.") { 378 _, fname := filepath.Split(f.File) 379 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 380 } 381 fmt.Println(f) 382 if !more { 383 break 384 } 385 } 386 if v := fmt.Sprint(list); v != infos { 387 panic(v) 388 } 389 }() 390 g() 391 } 392 393 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 main.g main.go:34 main.main main.go:60]" 394 ` 395 _, err := igop.RunFile("main.go", src, nil, 0) 396 if err != nil { 397 t.Fatal(err) 398 } 399 } 400 401 func TestRuntimeCallers5(t *testing.T) { 402 src := `package main 403 404 import ( 405 "fmt" 406 "path/filepath" 407 "runtime" 408 "strings" 409 ) 410 411 var t *struct { 412 c chan int 413 } 414 415 var c chan int 416 417 func f() { 418 select { 419 case <-t.c: // THIS IS LINE 18 420 break 421 case <-c: 422 break 423 } 424 } 425 426 func g() { 427 defer func() { 428 // panic("error g1") 429 }() 430 defer func() { 431 // panic("error g2") 432 f() 433 }() 434 f() 435 } 436 437 func main() { 438 defer func() { 439 recover() 440 rpc := make([]uintptr, 64) 441 runtime.Callers(0, rpc) 442 fs := runtime.CallersFrames(rpc) 443 var list []string 444 for { 445 f, more := fs.Next() 446 if f.Function == "runtime.gopanic" { 447 list = append(list, "runtime.gopanic") 448 } else if strings.HasPrefix(f.Function, "main.") { 449 _, fname := filepath.Split(f.File) 450 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 451 } 452 fmt.Println(f) 453 if !more { 454 break 455 } 456 } 457 if v := fmt.Sprint(list); v != infos { 458 panic(v) 459 } 460 }() 461 g() 462 } 463 464 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 runtime.gopanic main.f main.go:18 main.g main.go:33 main.main main.go:60]" 465 ` 466 _, err := igop.RunFile("main.go", src, nil, 0) 467 if err != nil { 468 t.Fatal(err) 469 } 470 } 471 472 func TestRuntimeCallers6(t *testing.T) { 473 src := `package main 474 475 import ( 476 "fmt" 477 "path/filepath" 478 "runtime" 479 "strings" 480 ) 481 482 var t *struct { 483 c chan int 484 } 485 486 var c chan int 487 488 func f() { 489 select { 490 case <-t.c: // THIS IS LINE 18 491 break 492 case <-c: 493 break 494 } 495 } 496 497 func g() { 498 defer func() { 499 panic("error g1") 500 }() 501 defer func() { 502 // panic("error g2") 503 f() 504 }() 505 // f() 506 } 507 508 func main() { 509 defer func() { 510 recover() 511 rpc := make([]uintptr, 64) 512 runtime.Callers(0, rpc) 513 fs := runtime.CallersFrames(rpc) 514 var list []string 515 for { 516 f, more := fs.Next() 517 if f.Function == "runtime.gopanic" { 518 list = append(list, "runtime.gopanic") 519 } else if strings.HasPrefix(f.Function, "main.") { 520 _, fname := filepath.Split(f.File) 521 list = append(list, fmt.Sprintf("%v %v:%v", f.Function, fname, f.Line)) 522 } 523 fmt.Println(f) 524 if !more { 525 break 526 } 527 } 528 if v := fmt.Sprint(list); v != infos { 529 panic(v) 530 } 531 }() 532 g() 533 } 534 535 var infos = "[main.main.func1 main.go:40 runtime.gopanic main.g.func1 main.go:27 runtime.gopanic main.f main.go:18 main.g.func2 main.go:31 main.g main.go:34 main.main main.go:60]" 536 ` 537 _, err := igop.RunFile("main.go", src, nil, 0) 538 if err != nil { 539 t.Fatal(err) 540 } 541 } 542 543 func TestRuntimeCallerMethodWrapper(t *testing.T) { 544 src := `package main 545 546 import ( 547 "fmt" 548 "reflect" 549 "runtime" 550 "strings" 551 ) 552 553 type T int 554 555 func (T) f() int { return 0 } 556 557 func (*T) g() int { return 0 } 558 559 type I interface { 560 f() int 561 } 562 563 var ( 564 index int 565 ) 566 567 func check(v interface{}, name string, autogen bool) { 568 index++ 569 pc := reflect.ValueOf(v).Pointer() 570 fn := runtime.FuncForPC(pc) 571 typ := reflect.ValueOf(v).Type() 572 file, line := fn.FileLine(pc) 573 fmt.Println(typ, fn.Name(), file, line) 574 if name != "" && name != fn.Name() { 575 panic(fmt.Errorf("%v: name got %v, want %v", index, fn.Name(), name)) 576 } 577 if autogen { 578 if file != "<autogenerated>" || line != 1 { 579 panic(fmt.Errorf("%v: file must autogen %v %v", index, file, line)) 580 } 581 } else { 582 if !strings.Contains(file, "main.go") { 583 panic(fmt.Errorf("%v: file must main.go %v %v", index, file, line)) 584 } 585 } 586 } 587 588 func main() { 589 ver := runtime.Version()[:6] 590 if ver < "go1.18" { 591 // $thunk 592 check(T.f, "main.T.f", false) 593 check((*T).g, "main.(*T).g", false) 594 check((struct{ T }).f, "", true) 595 check((struct{ *T }).g, "", true) 596 // $bound 597 check(T(0).f, "main.T.f-fm", false) 598 check(new(T).f, "main.T.f-fm", false) 599 check(new(T).g, "main.(*T).g-fm", false) 600 // wrapper 601 check(I.f, "main.I.f", true) 602 } else { 603 // $thunk 604 check(T.f, "main.T.f", false) 605 check((*T).g, "main.(*T).g", false) 606 check((struct{ T }).f, "", true) 607 check((struct{ *T }).g, "", true) 608 // $bound 609 check(T(0).f, "main.T.f-fm", true) 610 check(new(T).f, "main.T.f-fm", true) 611 check(new(T).g, "main.(*T).g-fm", true) 612 // wrapper 613 check(I.f, "main.I.f", true) 614 } 615 } 616 ` 617 _, err := igop.RunFile("main.go", src, nil, 0) 618 if err != nil { 619 t.Fatal(err) 620 } 621 } 622 623 func TestGC15281(t *testing.T) { 624 // $GOROOT/test/fixedbugs/issue15281.go 625 src := `// run 626 627 // Copyright 2016 The Go Authors. All rights reserved. 628 // Use of this source code is governed by a BSD-style 629 // license that can be found in the LICENSE file. 630 631 package main 632 633 import "runtime" 634 635 func main() { 636 { 637 x := inuse() 638 c := make(chan []byte, 10) 639 c <- make([]byte, 10<<20) 640 close(c) 641 f1(c, x) 642 } 643 { 644 x := inuse() 645 c := make(chan []byte, 10) 646 c <- make([]byte, 10<<20) 647 close(c) 648 f2(c, x) 649 } 650 } 651 652 func f1(c chan []byte, start int64) { 653 for x := range c { 654 if delta := inuse() - start; delta < 9<<20 { 655 println("BUG: f1: after alloc: expected delta at least 9MB, got: ", delta) 656 println(x) 657 } 658 x = nil 659 if delta := inuse() - start; delta > 1<<20 { 660 println("BUG: f1: after alloc: expected delta below 1MB, got: ", delta) 661 println(x) 662 } 663 } 664 } 665 666 func f2(c chan []byte, start int64) { 667 for { 668 x, ok := <-c 669 if !ok { 670 break 671 } 672 if delta := inuse() - start; delta < 9<<20 { 673 println("BUG: f2: after alloc: expected delta at least 9MB, got: ", delta) 674 println(x) 675 } 676 x = nil 677 if delta := inuse() - start; delta > 1<<20 { 678 println("BUG: f2: after alloc: expected delta below 1MB, got: ", delta) 679 println(x) 680 } 681 } 682 } 683 684 func inuse() int64 { 685 runtime.GC() 686 var st runtime.MemStats 687 runtime.ReadMemStats(&st) 688 return int64(st.Alloc) 689 } 690 ` 691 _, err := igop.RunFile("main.go", src, nil, igop.ExperimentalSupportGC) 692 if err != nil { 693 t.Fatal(err) 694 } 695 } 696 697 func TestLinknameSource(t *testing.T) { 698 pkg := `package pkg 699 type point struct { 700 x int 701 y int 702 } 703 func (t point) scale(n int) point { 704 return point{t.x*n,t.y*n} 705 } 706 func (t *point) setScale(n int) { 707 t.x *= n 708 t.y *= n 709 } 710 func (t *point) info() (int,int) { 711 return t.x,t.y 712 } 713 func add(v ...int) (sum int) { 714 for _, n := range v { 715 sum += n 716 } 717 return 718 } 719 func New(x int, y int) *point { 720 return &point{x,y} 721 } 722 ` 723 src := `package main 724 import ( 725 _ "unsafe" 726 _ "pkg" 727 "fmt" 728 ) 729 730 //go:linkname add pkg.add 731 func add(v ...int) int 732 733 type point struct { 734 x int 735 y int 736 } 737 738 //go:linkname newPoint pkg.New 739 func newPoint(x int, y int) *point 740 741 //go:linkname scalePoint pkg.point.scale 742 func scalePoint(point,int) point 743 744 //go:linkname setScale pkg.(*point).setScale 745 func setScale(*point,int) 746 747 func main() { 748 v := add(100,200,300) 749 if v != 600 { 750 panic(fmt.Errorf("add got %v, must 600",v)) 751 } 752 pt := newPoint(100,200) 753 if pt == nil || pt.x != 100 || pt.y != 200 { 754 panic(fmt.Errorf("newPoint got %v, must &{100 200}",pt)) 755 } 756 pt2 := scalePoint(*pt,2) 757 if pt2.x != 200 || pt2.y != 400 { 758 panic(fmt.Errorf("scalePoint got %v, must {200 400}",pt2)) 759 } 760 setScale(pt,3) 761 if pt.x != 300 || pt.y != 600 { 762 panic(fmt.Errorf("setScale got %v, must &{300 600}",pt)) 763 } 764 } 765 ` 766 ctx := igop.NewContext(0) 767 ctx.AddImportFile("pkg", "pkg.go", pkg) 768 _, err := ctx.RunFile("main.go", src, nil) 769 if err != nil { 770 t.Fatal(err) 771 } 772 } 773 774 func TestLinknameExtern(t *testing.T) { 775 pkg := `package pkg 776 func add(v ...int) (sum int) { 777 for _, n := range v { 778 sum += n 779 } 780 return 781 } 782 ` 783 src := `package main 784 import ( 785 _ "unsafe" 786 _ "pkg" 787 "fmt" 788 ) 789 790 //go:linkname add pkg.add 791 func add(v ...int) int 792 793 type point struct { 794 x int 795 y int 796 } 797 798 //go:linkname newPoint pkg.New 799 func newPoint(x int, y int) *point 800 801 //go:linkname scalePoint pkg.point.scale 802 func scalePoint(point,int) point 803 804 //go:linkname setScale pkg.(*point).setScale 805 func setScale(*point,int) 806 807 func main() { 808 v := add(100,200,300) 809 if v != 600 { 810 panic(fmt.Errorf("add got %v, must 600",v)) 811 } 812 pt := newPoint(100,200) 813 if pt == nil || pt.x != 100 || pt.y != 200 { 814 panic(fmt.Errorf("newPoint got %v, must &{100 200}",pt)) 815 } 816 pt2 := scalePoint(*pt,2) 817 if pt2.x != 200 || pt2.y != 400 { 818 panic(fmt.Errorf("scalePoint got %v, must {200 400}",pt2)) 819 } 820 setScale(pt,3) 821 if pt.x != 300 || pt.y != 600 { 822 panic(fmt.Errorf("setScale got %v, must &{300 600}",pt)) 823 } 824 } 825 ` 826 type point struct { 827 x int 828 y int 829 } 830 ctx := igop.NewContext(0) 831 ctx.AddImportFile("pkg", "pkg.go", pkg) 832 ctx.RegisterExternal("pkg.New", func(x int, y int) *point { 833 return &point{x, y} 834 }) 835 ctx.RegisterExternal("pkg.point.scale", func(pt point, n int) point { 836 return point{pt.x * n, pt.y * n} 837 }) 838 ctx.RegisterExternal("pkg.(*point).setScale", func(pt *point, n int) { 839 pt.x *= n 840 pt.y *= n 841 }) 842 _, err := ctx.RunFile("main.go", src, nil) 843 if err != nil { 844 t.Fatal(err) 845 } 846 } 847 848 func TestLinknameVar(t *testing.T) { 849 pkg := `package pkg 850 var n int = 100 851 func N() int { 852 return n 853 } 854 ` 855 src := `package main 856 import ( 857 _ "unsafe" 858 "pkg" 859 "fmt" 860 ) 861 862 //go:linkname v pkg.n 863 var v int 864 865 //go:linkname e pkg.e 866 var e int 867 868 func main() { 869 if v != 100 { 870 panic(fmt.Errorf("v got %v, must 100",v)) 871 } 872 v = 200 873 if pkg.N() != 200 { 874 panic(fmt.Errorf("pkg.N got %v, must 200",pkg.N())) 875 } 876 if e != 100 { 877 panic(fmt.Errorf("3 got %v, must 100",e)) 878 } 879 } 880 ` 881 ctx := igop.NewContext(0) 882 ctx.AddImportFile("pkg", "pkg.go", pkg) 883 var e int = 100 884 ctx.RegisterExternal("pkg.e", &e) 885 _, err := ctx.RunFile("main.go", src, nil) 886 if err != nil { 887 t.Fatal(err) 888 } 889 } 890 891 func TestLinknamePkg(t *testing.T) { 892 src := `package main 893 import ( 894 _ "unsafe" 895 _ "strings" 896 "os" 897 "bytes" 898 ) 899 900 //go:linkname stdout os.Stdout 901 var stdout *os.File 902 903 //go:linkname join strings.Join 904 func join(elems []string, sep string) string 905 906 //go:linkname writeBuffer bytes.(*Buffer).Write 907 func writeBuffer(buf *bytes.Buffer, data []byte) (n int, err error) 908 909 func main() { 910 if stdout != os.Stdout { 911 panic("error stdout") 912 } 913 if v := join([]string{"hello","world"},","); v != "hello,world" { 914 panic("error join "+v) 915 } 916 var buf bytes.Buffer 917 writeBuffer(&buf,[]byte("hello")) 918 if v := buf.String(); v != "hello" { 919 panic("error write buffer "+v) 920 } 921 } 922 ` 923 ctx := igop.NewContext(0) 924 _, err := ctx.RunFile("main.go", src, nil) 925 if err != nil { 926 t.Fatal(err) 927 } 928 } 929 930 func TestLinknameError1(t *testing.T) { 931 pkg := `package pkg 932 func add(v ...int) (sum int) { 933 for _, n := range v { 934 sum += n 935 } 936 return 937 } 938 ` 939 src := `package main 940 import ( 941 _ "pkg" 942 ) 943 944 //go:linkname add pkg.add 945 func add(v ...int) int 946 947 func main() { 948 } 949 ` 950 ctx := igop.NewContext(0) 951 ctx.AddImportFile("pkg", "pkg.go", pkg) 952 _, err := ctx.RunFile("main.go", src, nil) 953 if err == nil { 954 t.Fatal("must error") 955 } 956 if err.Error() != `main.go:6:1: //go:linkname only allowed in Go files that import "unsafe"` { 957 t.Fatal(err) 958 } 959 } 960 961 func TestLinknameError2(t *testing.T) { 962 pkg := `package pkg 963 func add(v ...int) (sum int) { 964 for _, n := range v { 965 sum += n 966 } 967 return 968 } 969 ` 970 src := `package main 971 import ( 972 _ "unsafe" 973 _ "pkg" 974 ) 975 976 //go:linkname add2 pkg.add 977 func add(v ...int) int 978 979 func main() { 980 } 981 ` 982 ctx := igop.NewContext(0) 983 ctx.AddImportFile("pkg", "pkg.go", pkg) 984 _, err := ctx.RunFile("main.go", src, nil) 985 if err == nil { 986 t.Fatal("must error") 987 } 988 if err.Error() != `main.go:7:1: //go:linkname must refer to declared function or variable` { 989 t.Fatal(err) 990 } 991 } 992 993 func TestLinknameError3(t *testing.T) { 994 pkg := `package pkg 995 var v int = 100 996 ` 997 src := `package main 998 import ( 999 _ "unsafe" 1000 _ "pkg" 1001 ) 1002 1003 //go:linkname a pkg.v 1004 var a int = 200 1005 1006 func main() { 1007 } 1008 ` 1009 ctx := igop.NewContext(0) 1010 ctx.AddImportFile("pkg", "pkg.go", pkg) 1011 _, err := ctx.RunFile("main.go", src, nil) 1012 if err == nil { 1013 t.Fatal("must error") 1014 } 1015 if err.Error() != `duplicated definition of symbol pkg.v, from main and pkg` { 1016 t.Fatal(err) 1017 } 1018 }