Source file
src/runtime/cgocheck.go
Documentation: runtime
1
2
3
4
5
6
7
8 package runtime
9
10 import (
11 "runtime/internal/sys"
12 "unsafe"
13 )
14
15 const cgoWriteBarrierFail = "Go pointer stored into non-Go memory"
16
17
18
19
20
21
22
23
24
25 func cgoCheckWriteBarrier(dst *uintptr, src uintptr) {
26 if !cgoIsGoPointer(unsafe.Pointer(src)) {
27 return
28 }
29 if cgoIsGoPointer(unsafe.Pointer(dst)) {
30 return
31 }
32
33
34
35 g := getg()
36 if g == g.m.g0 || g == g.m.gsignal {
37 return
38 }
39
40
41
42 if g.m.mallocing != 0 {
43 return
44 }
45
46 systemstack(func() {
47 println("write of Go pointer", hex(src), "to non-Go memory", hex(uintptr(unsafe.Pointer(dst))))
48 throw(cgoWriteBarrierFail)
49 })
50 }
51
52
53
54
55
56
57
58
59 func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
60 if typ.kind&kindNoPointers != 0 {
61 return
62 }
63 if !cgoIsGoPointer(src) {
64 return
65 }
66 if cgoIsGoPointer(dst) {
67 return
68 }
69 cgoCheckTypedBlock(typ, src, off, size)
70 }
71
72
73
74
75
76
77
78 func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
79 if typ.kind&kindNoPointers != 0 {
80 return
81 }
82 if !cgoIsGoPointer(src.array) {
83 return
84 }
85 if cgoIsGoPointer(dst.array) {
86 return
87 }
88 p := src.array
89 for i := 0; i < n; i++ {
90 cgoCheckTypedBlock(typ, p, 0, typ.size)
91 p = add(p, typ.size)
92 }
93 }
94
95
96
97
98
99
100 func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
101
102 if typ.ptrdata <= off {
103 return
104 }
105 if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
106 size = ptrdataSize
107 }
108
109 if typ.kind&kindGCProg == 0 {
110 cgoCheckBits(src, typ.gcdata, off, size)
111 return
112 }
113
114
115 for _, datap := range activeModules() {
116 if cgoInRange(src, datap.data, datap.edata) {
117 doff := uintptr(src) - datap.data
118 cgoCheckBits(add(src, -doff), datap.gcdatamask.bytedata, off+doff, size)
119 return
120 }
121 if cgoInRange(src, datap.bss, datap.ebss) {
122 boff := uintptr(src) - datap.bss
123 cgoCheckBits(add(src, -boff), datap.gcbssmask.bytedata, off+boff, size)
124 return
125 }
126 }
127
128 aoff := uintptr(src) - mheap_.arena_start
129 idx := aoff >> _PageShift
130 s := mheap_.spans[idx]
131 if s.state == _MSpanManual {
132
133
134
135
136
137
138
139 systemstack(func() {
140 cgoCheckUsingType(typ, src, off, size)
141 })
142 return
143 }
144
145
146
147 hbits := heapBitsForAddr(uintptr(src))
148 for i := uintptr(0); i < off+size; i += sys.PtrSize {
149 bits := hbits.bits()
150 if i >= off && bits&bitPointer != 0 {
151 v := *(*unsafe.Pointer)(add(src, i))
152 if cgoIsGoPointer(v) {
153 systemstack(func() {
154 throw(cgoWriteBarrierFail)
155 })
156 }
157 }
158 hbits = hbits.next()
159 }
160 }
161
162
163
164
165
166
167 func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
168 skipMask := off / sys.PtrSize / 8
169 skipBytes := skipMask * sys.PtrSize * 8
170 ptrmask := addb(gcbits, skipMask)
171 src = add(src, skipBytes)
172 off -= skipBytes
173 size += off
174 var bits uint32
175 for i := uintptr(0); i < size; i += sys.PtrSize {
176 if i&(sys.PtrSize*8-1) == 0 {
177 bits = uint32(*ptrmask)
178 ptrmask = addb(ptrmask, 1)
179 } else {
180 bits >>= 1
181 }
182 if off > 0 {
183 off -= sys.PtrSize
184 } else {
185 if bits&1 != 0 {
186 v := *(*unsafe.Pointer)(add(src, i))
187 if cgoIsGoPointer(v) {
188 systemstack(func() {
189 throw(cgoWriteBarrierFail)
190 })
191 }
192 }
193 }
194 }
195 }
196
197
198
199
200
201
202
203
204 func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
205 if typ.kind&kindNoPointers != 0 {
206 return
207 }
208
209
210 if typ.ptrdata <= off {
211 return
212 }
213 if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
214 size = ptrdataSize
215 }
216
217 if typ.kind&kindGCProg == 0 {
218 cgoCheckBits(src, typ.gcdata, off, size)
219 return
220 }
221 switch typ.kind & kindMask {
222 default:
223 throw("can't happen")
224 case kindArray:
225 at := (*arraytype)(unsafe.Pointer(typ))
226 for i := uintptr(0); i < at.len; i++ {
227 if off < at.elem.size {
228 cgoCheckUsingType(at.elem, src, off, size)
229 }
230 src = add(src, at.elem.size)
231 skipped := off
232 if skipped > at.elem.size {
233 skipped = at.elem.size
234 }
235 checked := at.elem.size - skipped
236 off -= skipped
237 if size <= checked {
238 return
239 }
240 size -= checked
241 }
242 case kindStruct:
243 st := (*structtype)(unsafe.Pointer(typ))
244 for _, f := range st.fields {
245 if off < f.typ.size {
246 cgoCheckUsingType(f.typ, src, off, size)
247 }
248 src = add(src, f.typ.size)
249 skipped := off
250 if skipped > f.typ.size {
251 skipped = f.typ.size
252 }
253 checked := f.typ.size - skipped
254 off -= skipped
255 if size <= checked {
256 return
257 }
258 size -= checked
259 }
260 }
261 }
262
View as plain text