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