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