Source file
src/runtime/cgocheck.go
1
2
3
4
5
6
7
8 package runtime
9
10 import (
11 "internal/abi"
12 "internal/goarch"
13 "unsafe"
14 )
15
16 const cgoWriteBarrierFail = "unpinned Go pointer stored into non-Go memory"
17
18
19
20
21
22
23
24
25
26 func cgoCheckPtrWrite(dst *unsafe.Pointer, src unsafe.Pointer) {
27 if !mainStarted {
28
29
30
31 return
32 }
33 if !cgoIsGoPointer(src) {
34 return
35 }
36 if cgoIsGoPointer(unsafe.Pointer(dst)) {
37 return
38 }
39
40
41
42 gp := getg()
43 if gp == gp.m.g0 || gp == gp.m.gsignal {
44 return
45 }
46
47
48
49 if gp.m.mallocing != 0 {
50 return
51 }
52
53
54
55 if isPinned(src) {
56 return
57 }
58
59
60
61
62 if inPersistentAlloc(uintptr(unsafe.Pointer(dst))) {
63 return
64 }
65
66 systemstack(func() {
67 println("write of unpinned Go pointer", hex(uintptr(src)), "to non-Go memory", hex(uintptr(unsafe.Pointer(dst))))
68 throw(cgoWriteBarrierFail)
69 })
70 }
71
72
73
74
75
76
77
78
79
80 func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer) {
81 cgoCheckMemmove2(typ, dst, src, 0, typ.Size_)
82 }
83
84
85
86
87
88
89
90
91
92 func cgoCheckMemmove2(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
93 if !typ.Pointers() {
94 return
95 }
96 if !cgoIsGoPointer(src) {
97 return
98 }
99 if cgoIsGoPointer(dst) {
100 return
101 }
102 cgoCheckTypedBlock(typ, src, off, size)
103 }
104
105
106
107
108
109
110
111
112
113 func cgoCheckSliceCopy(typ *_type, dst, src unsafe.Pointer, n int) {
114 if !typ.Pointers() {
115 return
116 }
117 if !cgoIsGoPointer(src) {
118 return
119 }
120 if cgoIsGoPointer(dst) {
121 return
122 }
123 p := src
124 for i := 0; i < n; i++ {
125 cgoCheckTypedBlock(typ, p, 0, typ.Size_)
126 p = add(p, typ.Size_)
127 }
128 }
129
130
131
132
133
134
135
136 func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
137
138 if typ.PtrBytes <= off {
139 return
140 }
141 if ptrdataSize := typ.PtrBytes - off; size > ptrdataSize {
142 size = ptrdataSize
143 }
144
145 if typ.Kind_&abi.KindGCProg == 0 {
146 cgoCheckBits(src, typ.GCData, off, size)
147 return
148 }
149
150
151 for _, datap := range activeModules() {
152 if cgoInRange(src, datap.data, datap.edata) {
153 doff := uintptr(src) - datap.data
154 cgoCheckBits(add(src, -doff), datap.gcdatamask.bytedata, off+doff, size)
155 return
156 }
157 if cgoInRange(src, datap.bss, datap.ebss) {
158 boff := uintptr(src) - datap.bss
159 cgoCheckBits(add(src, -boff), datap.gcbssmask.bytedata, off+boff, size)
160 return
161 }
162 }
163
164 s := spanOfUnchecked(uintptr(src))
165 if s.state.get() == mSpanManual {
166
167
168
169
170
171
172
173 systemstack(func() {
174 cgoCheckUsingType(typ, src, off, size)
175 })
176 return
177 }
178
179
180 tp := s.typePointersOf(uintptr(src), size)
181 for {
182 var addr uintptr
183 if tp, addr = tp.next(uintptr(src) + size); 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.Pointers() {
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_&abi.KindGCProg == 0 {
249 cgoCheckBits(src, typ.GCData, off, size)
250 return
251 }
252 switch typ.Kind_ & abi.KindMask {
253 default:
254 throw("can't happen")
255 case abi.Array:
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 abi.Struct:
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