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