Source file src/cmd/cgo/internal/test/testx.go

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

View as plain text