1// Copyright 2011 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// Test cases for cgo. 6// Both the import "C" prologue and the main file are sorted by issue number. 7// This file contains //export directives on Go functions 8// and so it must NOT contain C definitions (only declarations). 9// See test.go for C definitions. 10 11package cgotest 12 13import ( 14 "runtime" 15 "runtime/cgo" 16 "runtime/debug" 17 "strings" 18 "sync" 19 "sync/atomic" 20 "testing" 21 "unsafe" 22) 23 24/* 25// threads 26extern void doAdd(int, int); 27extern int callGoInCThread(int); 28 29// issue 1328 30void IntoC(void); 31 32// issue 1560 33extern void Issue1560InC(void); 34 35// twoSleep returns the absolute start time of the first sleep 36// in ms. 37long long twoSleep(int); 38 39// issue 3775 40void lockOSThreadC(void); 41int usleep(unsigned usec); 42 43// issue 4054 part 2 - part 1 in test.go 44typedef enum { 45 A = 0, 46 B, 47 C, 48 D, 49 E, 50 F, 51 G, 52 H, 53 II, 54 J, 55} issue4054b; 56 57// issue 5548 58 59extern int issue5548_in_c(void); 60 61// issue 6833 62 63extern unsigned long long issue6833Func(unsigned int, unsigned long long); 64 65// issue 6907 66 67extern int CheckIssue6907C(_GoString_); 68 69// issue 7665 70 71extern void f7665(void); 72 73// issue 7978 74// Stack tracing didn't work during cgo code after calling a Go 75// callback. Make sure GC works and the stack trace is correct. 76 77#include <stdint.h> 78 79// use ugly atomic variable sync since that doesn't require calling back into 80// Go code or OS dependencies 81void issue7978c(uint32_t *sync); 82 83// issue 8331 part 2 - part 1 in test.go 84// A typedef of an unnamed struct is the same struct when 85// #include'd twice. No runtime test; just make sure it compiles. 86#include "issue8331.h" 87 88// issue 8945 89 90typedef void (*PFunc8945)(); 91extern PFunc8945 func8945; // definition is in test.go 92 93// issue 20910 94void callMulti(void); 95 96// issue 28772 part 2 - part 1 in issuex.go 97#define issue28772Constant2 2 98 99 100// issue 31891 101typedef struct { 102 long obj; 103} Issue31891A; 104 105typedef struct { 106 long obj; 107} Issue31891B; 108 109void callIssue31891(void); 110 111typedef struct { 112 int i; 113} Issue38408, *PIssue38408; 114 115extern void cfunc49633(void*); // definition is in test.go 116*/ 117import "C" 118 119// exports 120 121//export ReturnIntLong 122func ReturnIntLong() (int, C.long) { 123 return 1, 2 124} 125 126//export gc 127func gc() { 128 runtime.GC() 129} 130 131// threads 132 133var sum struct { 134 sync.Mutex 135 i int 136} 137 138//export Add 139func Add(x int) { 140 defer func() { 141 recover() 142 }() 143 sum.Lock() 144 sum.i += x 145 sum.Unlock() 146 var p *int 147 *p = 2 148} 149 150//export goDummy 151func goDummy() { 152} 153 154func testCthread(t *testing.T) { 155 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" { 156 t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add") 157 } 158 sum.i = 0 159 C.doAdd(10, 6) 160 161 want := 10 * (10 - 1) / 2 * 6 162 if sum.i != want { 163 t.Fatalf("sum=%d, want %d", sum.i, want) 164 } 165} 166 167// Benchmark measuring overhead from C to Go in a C thread. 168// Create a new C thread and invoke Go function repeatedly in the new C thread. 169func benchCGoInCthread(b *testing.B) { 170 n := C.callGoInCThread(C.int(b.N)) 171 if int(n) != b.N { 172 b.Fatal("unmatch loop times") 173 } 174} 175 176// issue 1328 177 178//export BackIntoGo 179func BackIntoGo() { 180 x := 1 181 182 for i := 0; i < 10000; i++ { 183 xvariadic(x) 184 if x != 1 { 185 panic("x is not 1?") 186 } 187 } 188} 189 190func xvariadic(x ...interface{}) { 191} 192 193func test1328(t *testing.T) { 194 C.IntoC() 195} 196 197// issue 1560 198// Test that C functions and Go functions run in parallel. 199 200var ( 201 issue1560 int32 202 203 issue1560Ch = make(chan bool, 2) 204) 205 206//export Issue1560FromC 207func Issue1560FromC() { 208 for atomic.LoadInt32(&issue1560) != 1 { 209 runtime.Gosched() 210 } 211 atomic.AddInt32(&issue1560, 1) 212 for atomic.LoadInt32(&issue1560) != 3 { 213 runtime.Gosched() 214 } 215 issue1560Ch <- true 216} 217 218func Issue1560FromGo() { 219 atomic.AddInt32(&issue1560, 1) 220 for atomic.LoadInt32(&issue1560) != 2 { 221 runtime.Gosched() 222 } 223 atomic.AddInt32(&issue1560, 1) 224 issue1560Ch <- true 225} 226 227func test1560(t *testing.T) { 228 go Issue1560FromGo() 229 go C.Issue1560InC() 230 <-issue1560Ch 231 <-issue1560Ch 232} 233 234// issue 2462 235 236//export exportbyte 237func exportbyte() byte { 238 return 0 239} 240 241//export exportbool 242func exportbool() bool { 243 return false 244} 245 246//export exportrune 247func exportrune() rune { 248 return 0 249} 250 251//export exporterror 252func exporterror() error { 253 return nil 254} 255 256//export exportint 257func exportint() int { 258 return 0 259} 260 261//export exportuint 262func exportuint() uint { 263 return 0 264} 265 266//export exportuintptr 267func exportuintptr() uintptr { 268 return (uintptr)(0) 269} 270 271//export exportint8 272func exportint8() int8 { 273 return 0 274} 275 276//export exportuint8 277func exportuint8() uint8 { 278 return 0 279} 280 281//export exportint16 282func exportint16() int16 { 283 return 0 284} 285 286//export exportuint16 287func exportuint16() uint16 { 288 return 0 289} 290 291//export exportint32 292func exportint32() int32 { 293 return 0 294} 295 296//export exportuint32 297func exportuint32() uint32 { 298 return 0 299} 300 301//export exportint64 302func exportint64() int64 { 303 return 0 304} 305 306//export exportuint64 307func exportuint64() uint64 { 308 return 0 309} 310 311//export exportfloat32 312func exportfloat32() float32 { 313 return 0 314} 315 316//export exportfloat64 317func exportfloat64() float64 { 318 return 0 319} 320 321//export exportcomplex64 322func exportcomplex64() complex64 { 323 return 0 324} 325 326//export exportcomplex128 327func exportcomplex128() complex128 { 328 return 0 329} 330 331// issue 3741 332 333//export exportSliceIn 334func exportSliceIn(s []byte) bool { 335 return len(s) == cap(s) 336} 337 338//export exportSliceOut 339func exportSliceOut() []byte { 340 return []byte{1} 341} 342 343//export exportSliceInOut 344func exportSliceInOut(s []byte) []byte { 345 return s 346} 347 348// issue 3775 349 350func init() { 351 if runtime.GOOS == "android" { 352 return 353 } 354 // Same as test3775 but run during init so that 355 // there are two levels of internal runtime lock 356 // (1 for init, 1 for cgo). 357 // This would have been broken by CL 11663043. 358 C.lockOSThreadC() 359} 360 361func test3775(t *testing.T) { 362 if runtime.GOOS == "android" { 363 return 364 } 365 // Used to panic because of the UnlockOSThread below. 366 C.lockOSThreadC() 367} 368 369//export lockOSThreadCallback 370func lockOSThreadCallback() { 371 runtime.LockOSThread() 372 runtime.UnlockOSThread() 373 go C.usleep(10000) 374 runtime.Gosched() 375} 376 377// issue 4054 part 2 - part 1 in test.go 378 379var issue4054b = []int{C.A, C.B, C.C, C.D, C.E, C.F, C.G, C.H, C.II, C.J} 380 381//export issue5548FromC 382func issue5548FromC(s string, i int) int { 383 if len(s) == 4 && s == "test" && i == 42 { 384 return 12345 385 } 386 println("got", len(s), i) 387 return 9876 388} 389 390func test5548(t *testing.T) { 391 if x := C.issue5548_in_c(); x != 12345 { 392 t.Errorf("issue5548_in_c = %d, want %d", x, 12345) 393 } 394} 395 396// issue 6833 397 398//export GoIssue6833Func 399func GoIssue6833Func(aui uint, aui64 uint64) uint64 { 400 return aui64 + uint64(aui) 401} 402 403func test6833(t *testing.T) { 404 ui := 7 405 ull := uint64(0x4000300020001000) 406 v := uint64(C.issue6833Func(C.uint(ui), C.ulonglong(ull))) 407 exp := uint64(ui) + ull 408 if v != exp { 409 t.Errorf("issue6833Func() returns %x, expected %x", v, exp) 410 } 411} 412 413// issue 6907 414 415const CString = "C string" 416 417//export CheckIssue6907Go 418func CheckIssue6907Go(s string) C.int { 419 if s == CString { 420 return 1 421 } 422 return 0 423} 424 425func test6907Go(t *testing.T) { 426 if got := C.CheckIssue6907C(CString); got != 1 { 427 t.Errorf("C.CheckIssue6907C() == %d, want %d", got, 1) 428 } 429} 430 431// issue 7665 432 433var bad7665 unsafe.Pointer = C.f7665 434var good7665 uintptr = uintptr(C.f7665) 435 436func test7665(t *testing.T) { 437 if bad7665 == nil || uintptr(bad7665) != good7665 { 438 t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665) 439 } 440} 441 442// issue 7978 443 444var issue7978sync uint32 445 446func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) { 447 runtime.GC() 448 buf := make([]byte, 65536) 449 trace := string(buf[:runtime.Stack(buf, true)]) 450 for _, goroutine := range strings.Split(trace, "\n\n") { 451 if strings.Contains(goroutine, "test.issue7978go") { 452 trace := strings.Split(goroutine, "\n") 453 // look for the expected function in the stack 454 for i := 0; i < depth; i++ { 455 if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) { 456 t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine) 457 return 458 } 459 if strings.Contains(trace[1+2*i], wantFunc) { 460 return 461 } 462 } 463 t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine) 464 return 465 } 466 } 467 t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace) 468} 469 470func issue7978wait(store uint32, wait uint32) { 471 if store != 0 { 472 atomic.StoreUint32(&issue7978sync, store) 473 } 474 for atomic.LoadUint32(&issue7978sync) != wait { 475 runtime.Gosched() 476 } 477} 478 479//export issue7978cb 480func issue7978cb() { 481 // Force a stack growth from the callback to put extra 482 // pressure on the runtime. See issue #17785. 483 growStack(64) 484 issue7978wait(3, 4) 485} 486 487func growStack(n int) int { 488 var buf [128]int 489 if n == 0 { 490 return 0 491 } 492 return buf[growStack(n-1)] 493} 494 495func issue7978go() { 496 C.issue7978c((*C.uint32_t)(&issue7978sync)) 497 issue7978wait(7, 8) 498} 499 500func test7978(t *testing.T) { 501 if runtime.Compiler == "gccgo" { 502 t.Skip("gccgo can not do stack traces of C code") 503 } 504 debug.SetTraceback("2") 505 issue7978sync = 0 506 go issue7978go() 507 // test in c code, before callback 508 issue7978wait(0, 1) 509 issue7978check(t, "_Cfunc_issue7978c(", "", 1) 510 // test in go code, during callback 511 issue7978wait(2, 3) 512 issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3) 513 // test in c code, after callback 514 issue7978wait(4, 5) 515 issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1) 516 // test in go code, after return from cgo 517 issue7978wait(6, 7) 518 issue7978check(t, "test.issue7978go(", "", 3) 519 atomic.StoreUint32(&issue7978sync, 8) 520} 521 522// issue 8331 part 2 523 524var issue8331Var C.issue8331 525 526// issue 8945 527 528//export Test8945 529func Test8945() { 530 _ = C.func8945 531} 532 533// issue 20910 534 535//export multi 536func multi() (*C.char, C.int) { 537 return C.CString("multi"), 0 538} 539 540func test20910(t *testing.T) { 541 C.callMulti() 542} 543 544// issue 28772 part 2 545 546const issue28772Constant2 = C.issue28772Constant2 547 548// issue 31891 549 550//export useIssue31891A 551func useIssue31891A(c *C.Issue31891A) {} 552 553//export useIssue31891B 554func useIssue31891B(c *C.Issue31891B) {} 555 556func test31891(t *testing.T) { 557 C.callIssue31891() 558} 559 560// issue 37033, check if cgo.Handle works properly 561 562var issue37033 = 42 563 564//export GoFunc37033 565func GoFunc37033(handle C.uintptr_t) { 566 h := cgo.Handle(handle) 567 ch := h.Value().(chan int) 568 ch <- issue37033 569} 570 571// issue 38408 572// A typedef pointer can be used as the element type. 573// No runtime test; just make sure it compiles. 574var _ C.PIssue38408 = &C.Issue38408{i: 1} 575 576// issue 49633, example use of cgo.Handle with void* 577 578type data49633 struct { 579 msg string 580} 581 582//export GoFunc49633 583func GoFunc49633(context unsafe.Pointer) { 584 h := *(*cgo.Handle)(context) 585 v := h.Value().(*data49633) 586 v.msg = "hello" 587} 588 589func test49633(t *testing.T) { 590 v := &data49633{} 591 h := cgo.NewHandle(v) 592 defer h.Delete() 593 C.cfunc49633(unsafe.Pointer(&h)) 594 if v.msg != "hello" { 595 t.Errorf("msg = %q, want 'hello'", v.msg) 596 } 597} 598