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