Help us shape the future of Go! Take the 2026 Go Developer Survey

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

View as plain text