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