// Copyright 2015 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Code to check that pointer writes follow the cgo rules.// These functions are invoked via the write barrier when debug.cgocheck > 1.package runtimeimport ()constcgoWriteBarrierFail = "Go pointer stored into non-Go memory"// cgoCheckWriteBarrier is called whenever a pointer is stored into memory.// It throws if the program is storing a Go pointer into non-Go memory.//// This is called from the write barrier, so its entire call tree must// be nosplit.////go:nosplit//go:nowritebarrierfunc ( *uintptr, uintptr) {if !cgoIsGoPointer(unsafe.Pointer()) {return }ifcgoIsGoPointer(unsafe.Pointer()) {return }// If we are running on the system stack then dst might be an // address on the stack, which is OK. := getg()if == .m.g0 || == .m.gsignal {return }// Allocating memory can write to various mfixalloc structs // that look like they are non-Go memory.if .m.mallocing != 0 {return }// It's OK if writing to memory allocated by persistentalloc. // Do this check last because it is more expensive and rarely true. // If it is false the expense doesn't matter since we are crashing.ifinPersistentAlloc(uintptr(unsafe.Pointer())) {return }systemstack(func() {println("write of Go pointer", hex(), "to non-Go memory", hex(uintptr(unsafe.Pointer())))throw(cgoWriteBarrierFail) })}// cgoCheckMemmove is called when moving a block of memory.// dst and src point off bytes into the value to copy.// size is the number of bytes to copy.// It throws if the program is copying a block that contains a Go pointer// into non-Go memory.//go:nosplit//go:nowritebarrierfunc ( *_type, , unsafe.Pointer, , uintptr) {if .ptrdata == 0 {return }if !cgoIsGoPointer() {return }ifcgoIsGoPointer() {return }cgoCheckTypedBlock(, , , )}// cgoCheckSliceCopy is called when copying n elements of a slice.// src and dst are pointers to the first element of the slice.// typ is the element type of the slice.// It throws if the program is copying slice elements that contain Go pointers// into non-Go memory.//go:nosplit//go:nowritebarrierfunc ( *_type, , unsafe.Pointer, int) {if .ptrdata == 0 {return }if !cgoIsGoPointer() {return }ifcgoIsGoPointer() {return } := for := 0; < ; ++ {cgoCheckTypedBlock(, , 0, .size) = add(, .size) }}// cgoCheckTypedBlock checks the block of memory at src, for up to size bytes,// and throws if it finds a Go pointer. The type of the memory is typ,// and src is off bytes into that type.//go:nosplit//go:nowritebarrierfunc ( *_type, unsafe.Pointer, , uintptr) {// Anything past typ.ptrdata is not a pointer.if .ptrdata <= {return }if := .ptrdata - ; > { = }if .kind&kindGCProg == 0 {cgoCheckBits(, .gcdata, , )return }// The type has a GC program. Try to find GC bits somewhere else.for , := rangeactiveModules() {ifcgoInRange(, .data, .edata) { := uintptr() - .datacgoCheckBits(add(, -), .gcdatamask.bytedata, +, )return }ifcgoInRange(, .bss, .ebss) { := uintptr() - .bsscgoCheckBits(add(, -), .gcbssmask.bytedata, +, )return } } := spanOfUnchecked(uintptr())if .state.get() == mSpanManual {// There are no heap bits for value stored on the stack. // For a channel receive src might be on the stack of some // other goroutine, so we can't unwind the stack even if // we wanted to. // We can't expand the GC program without extra storage // space we can't easily get. // Fortunately we have the type information.systemstack(func() {cgoCheckUsingType(, , , ) })return }// src must be in the regular heap. := heapBitsForAddr(uintptr())for := uintptr(0); < +; += sys.PtrSize { := .bits()if >= && &bitPointer != 0 { := *(*unsafe.Pointer)(add(, ))ifcgoIsGoPointer() {throw(cgoWriteBarrierFail) } } = .next() }}// cgoCheckBits checks the block of memory at src, for up to size// bytes, and throws if it finds a Go pointer. The gcbits mark each// pointer value. The src pointer is off bytes into the gcbits.//go:nosplit//go:nowritebarrierfunc ( unsafe.Pointer, *byte, , uintptr) { := / sys.PtrSize / 8 := * sys.PtrSize * 8 := addb(, ) = add(, ) -= += varuint32for := uintptr(0); < ; += sys.PtrSize {if &(sys.PtrSize*8-1) == 0 { = uint32(*) = addb(, 1) } else { >>= 1 }if > 0 { -= sys.PtrSize } else {if &1 != 0 { := *(*unsafe.Pointer)(add(, ))ifcgoIsGoPointer() {throw(cgoWriteBarrierFail) } } } }}// cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch// fall back to look for pointers in src using the type information.// We only use this when looking at a value on the stack when the type// uses a GC program, because otherwise it's more efficient to use the// GC bits. This is called on the system stack.//go:nowritebarrier//go:systemstackfunc ( *_type, unsafe.Pointer, , uintptr) {if .ptrdata == 0 {return }// Anything past typ.ptrdata is not a pointer.if .ptrdata <= {return }if := .ptrdata - ; > { = }if .kind&kindGCProg == 0 {cgoCheckBits(, .gcdata, , )return }switch .kind & kindMask {default:throw("can't happen")casekindArray: := (*arraytype)(unsafe.Pointer())for := uintptr(0); < .len; ++ {if < .elem.size { (.elem, , , ) } = add(, .elem.size) := if > .elem.size { = .elem.size } := .elem.size - -= if <= {return } -= }casekindStruct: := (*structtype)(unsafe.Pointer())for , := range .fields {if < .typ.size { (.typ, , , ) } = add(, .typ.size) := if > .typ.size { = .typ.size } := .typ.size - -= if <= {return } -= } }}