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.Pointers() {
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.Pointers() {
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 cgoCheckBits(src, getGCMask(typ), off, size)
145 }
146
147
148
149
150
151
152
153 func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
154 skipMask := off / goarch.PtrSize / 8
155 skipBytes := skipMask * goarch.PtrSize * 8
156 ptrmask := addb(gcbits, skipMask)
157 src = add(src, skipBytes)
158 off -= skipBytes
159 size += off
160 var bits uint32
161 for i := uintptr(0); i < size; i += goarch.PtrSize {
162 if i&(goarch.PtrSize*8-1) == 0 {
163 bits = uint32(*ptrmask)
164 ptrmask = addb(ptrmask, 1)
165 } else {
166 bits >>= 1
167 }
168 if off > 0 {
169 off -= goarch.PtrSize
170 } else {
171 if bits&1 != 0 {
172 v := *(*unsafe.Pointer)(add(src, i))
173 if cgoIsGoPointer(v) && !isPinned(v) {
174 throw(cgoWriteBarrierFail)
175 }
176 }
177 }
178 }
179 }
180
181
182
183
184
185
186
187
188
189 func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
190 if !typ.Pointers() {
191 return
192 }
193
194
195 if typ.PtrBytes <= off {
196 return
197 }
198 if ptrdataSize := typ.PtrBytes - off; size > ptrdataSize {
199 size = ptrdataSize
200 }
201
202 cgoCheckBits(src, getGCMask(typ), off, size)
203 }
204
View as plain text