This is a creation in Article, where the information may have evolved or changed.
In the early morning of February 18, 2016 in Beijing time, after go 1.5 released six months, go 1.6 officially release. The change to go 1.6 is small compared to go 1.5 's "big change" (mostly go), which is also related to go 1.6 's dev cycle being too short. But the go Community has paid much attention to the release, which is even more enthusiastic than go 1.5. At the initiative of Dave Cheney, Gophers held the Go 1.6 Release party around the world. Go Core team also opened a ama–ask Me anything,robpike, Russ Cox (RSC), Bradfitz and other go big gods in Reddit, to the majority of Gophers in 24hour within the question of a must answer.
Let's take a look at what changes in Go 1.6 deserve our attention. But before we talk about change, let's start with a mouth. Go 1.6 unchanged, that is, the Go Language language specification, still keep go 1 compatible unchanged. It is expected that we will not see any changes to go language specification in the next few stable release releases.
First, CGO
The CGO change is:
1, defined between go code and C code transfer pointer, that is, C code and go garbage collector coexistence of rules and restriction;
2, in the runtime added to the violation of the inspection, check the switch and intensity by godebug=cgocheck=1[0,2] control. 1 is the default, 0 is a close check, and 2 is a more thorough but costly check.
The proposal was proposed by Ian Lance Taylor. It is broadly divided into two situations:
(a) When Go calls C code
When Go calls C code, go pass to C code The go pointer refers to the go memory can not contain any point to go memory of the pointer. We are divided into several situations to explore:
1. Pass a pointer to the struct
//cgo1_struct.gopackage main/*#include <stdio.h>struct Foo{ int a; int *p;};void plusOne(struct Foo *f) { (f->a)++; *(f->p)++;}*/import "C"import "unsafe"import "fmt"func main() { f := &C.struct_Foo{} f.a = 5 f.p = (*C.int)((unsafe.Pointer)(new(int))) //f.p = &f.a C.plusOne(f) fmt.Println(int(f.a))}
As you can see from the Cgo1_struct.go code, go code passes a pointer f to C code that points to go memory (go Assignment), but F points to the go memory with a pointer p pointing to another go memory:new (int), Let's run this code:
$go run cgo1_struct.go# command-line-arguments./cgo1_struct.go:12:2: warning: expression result unused [-Wunused-value]panic: runtime error: cgo argument has Go pointer to Go pointergoroutine 1 [running]:panic(0x4068400, 0xc82000a110) /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main.main() /Users/tony/test/go/go16/cgo/cgo1_struct.go:24 +0xb9exit status 2
The code appears panic and prompts: "CGO argument has go pointer to go pointer". Our code violates the CGO pointer pass rule, even if f.p points to the struct's own memory, such as F.P = &F.A.
2. Pass a pointer to the struct field
As stated in the rules, if you pass a pointer to a struct field, "Go memory" refers to the memory occupied by the field, even if there are other field points in the struct that point to other Go memory matter:
//cgo1_structfield.gopackage main/*#include <stdio.h>struct Foo{ int a; int *p;};void plusOne(int *i) { (*i)++;}*/import "C"import ( "fmt" "unsafe")func main() { f := &C.struct_Foo{} f.a = 5 f.p = (*C.int)((unsafe.Pointer)(new(int))) C.plusOne(&f.a) fmt.Println(int(f.a))}
Operation result of the above program:
$go run cgo1_structfield.go6
3. Pass a pointer to element in the slice or array
Unlike transitive struct field, when passing a pointer to an element in a slice or array, the range of go memory to consider is not just this element, but the entire array or the underlying behind the entire slice The area of memory occupied by the array to ensure that no pointers to any go memory are included in this area. Let's look at the code example:
//cgo1_sliceelem.gopackage main/*#include <stdio.h>void plusOne(int **i) { (**i)++;}*/import "C"import ( "fmt" "unsafe")func main() { sl := make([]*int, 5) var a int = 5 sl[1] = &a C.plusOne((**C.int)((unsafe.Pointer)(&sl[0]))) fmt.Println(sl[0])}
From this code, we see that we are passing the address of the first element of slice, which is &sl[0]. We did not assign a value to Sl[0], but Sl[1] was assigned to another Go memory address (&a), and when we passed &sl[0] to PlusOne, the result was as follows:
$go run cgo1_sliceelem.gopanic: runtime error: cgo argument has Go pointer to Go pointergoroutine 1 [running]:panic(0x40dbac0, 0xc8200621d0) /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main.main() /Users/tony/test/go/go16/cgo/cgo1_sliceelem.go:19 +0xe4exit status 2
The runtime panic because of a violation of the rules.
(b) C when calling go code
1. The go function called by C cannot return a pointer to the memory of Go allocation
Let's look at the following example:
Cgo2_1.go
package main// extern int* goAdd(int, int);//// static int cAdd(int a, int b) {// int *i = goAdd(a, b);// return *i;// }import "C"import "fmt"//export goAddfunc goAdd(a, b C.int) *C.int { c := a + b return &c}func main() { var a, b int = 5, 6 i := C.cAdd(C.int(a), C.int(b)) fmt.Println(int(i))}
As you can see: Goadd this go function returns a pointer to the memory (&c) of Go allocation. Run the above code with the following results:
$go run cgo2_1.gopanic: runtime error: cgo result has Go pointergoroutine 1 [running]:panic(0x40dba40, 0xc82006e1c0) /Users/tony/.bin/go16/src/runtime/panic.go:464 +0x3e6main._cgoexpwrap_872b2f2e7532_goAdd.func1(0xc820049d98) command-line-arguments/_obj/_cgo_gotypes.go:64 +0x3amain._cgoexpwrap_872b2f2e7532_goAdd(0x600000005, 0xc82006e19c) command-line-arguments/_obj/_cgo_gotypes.go:66 +0x89main._Cfunc_cAdd(0x600000005, 0x0) command-line-arguments/_obj/_cgo_gotypes.go:45 +0x41main.main() /Users/tony/test/go/go16/cgo/cgo2_1.go:20 +0x35exit status 2
2. Go code cannot store pointers to go allocated memory in memory allocated by C
The following example simulates this situation:
//cgo2_2.gopackage main// #include <stdlib.h>// extern void goFoo(int**);//// static void cFoo() {// int **p = malloc(sizeof(int*));// goFoo(p);// }import "C"//export goFoofunc goFoo(p **C.int) { *p = new(C.int)}func main() { C.cFoo()}
However, for this example, the default godebug=cgocheck=1 bias is not a check problem. Let's change Godebug=cgocheck to =2:
$GODEBUG=cgocheck=2 go run cgo2_2.gowrite of Go pointer 0xc82000a0f8 to non-Go memory 0x4300000fatal error: Go pointer stored into non-Go memoryruntime stack:runtime.throw(0x4089800, 0x24) /Users/tony/.bin/go16/src/runtime/panic.go:530 +0x90runtime.cgoCheckWriteBarrier.func1() /Users/tony/.bin/go16/src/runtime/cgocheck.go:44 +0xaeruntime.systemstack(0x7fff5fbff8c0) /Users/tony/.bin/go16/src/runtime/asm_amd64.s:291 +0x79runtime.mstart() /Users/tony/.bin/go16/src/runtime/proc.go:1048... ...goroutine 17 [syscall, locked to thread]:runtime.goexit() /Users/tony/.bin/go16/src/runtime/asm_amd64.s:1998 +0x1exit status 2
Indeed runtime panic:write of Go pointer 0xc82000a0f8 to non-go memory 0x4300000