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