diff options
author | Matthew Dempsky <mdempsky@google.com> | 2019-10-21 17:45:59 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2019-10-22 18:09:15 +0000 |
commit | 5eec0a91eadd76a45197ee2588306bdc85570549 (patch) | |
tree | 93f80eeb7ba8e3db9b52c08325ce37c502feca45 /src/reflect | |
parent | a97ccc894032d646e3003f061704ca59cac2587f (diff) | |
download | go-5eec0a91eadd76a45197ee2588306bdc85570549.tar.gz go-5eec0a91eadd76a45197ee2588306bdc85570549.zip |
reflect: fix unsafe conversions reported by -d=checkptr
The code for generating gcdata was (technically) unsafe. It was also
rather repetitive. This CL refactors it a bit and abstracts use of
gcdata into a helper gcSlice method.
Updates #34972.
Change-Id: Ie86d7822eafe263f1d3d150eedf0ec66be1ec85d
Reviewed-on: https://go-review.googlesource.com/c/go/+/202582
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/export_test.go | 11 | ||||
-rw-r--r-- | src/reflect/type.go | 127 |
2 files changed, 62 insertions, 76 deletions
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 1c78570110..de426b58a8 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -36,11 +36,14 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, if ft.kind&kindGCProg != 0 { panic("can't handle gc programs") } - gcdata := (*[1000]byte)(unsafe.Pointer(ft.gcdata)) - for i := uintptr(0); i < ft.ptrdata/ptrSize; i++ { - gc = append(gc, gcdata[i/8]>>(i%8)&1) - } ptrs = ft.ptrdata != 0 + if ptrs { + nptrs := ft.ptrdata / ptrSize + gcdata := ft.gcSlice(0, (nptrs+7)/8) + for i := uintptr(0); i < nptrs; i++ { + gc = append(gc, gcdata[i/8]>>(i%8)&1) + } + } return } diff --git a/src/reflect/type.go b/src/reflect/type.go index e4b0432d42..06ca09576d 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2178,34 +2178,12 @@ func bucketOf(ktyp, etyp *rtype) *rtype { base := bucketSize / ptrSize if ktyp.ptrdata != 0 { - if ktyp.kind&kindGCProg != 0 { - panic("reflect: unexpected GC program in MapOf") - } - kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata)) - for i := uintptr(0); i < ktyp.ptrdata/ptrSize; i++ { - if (kmask[i/8]>>(i%8))&1 != 0 { - for j := uintptr(0); j < bucketSize; j++ { - word := base + j*ktyp.size/ptrSize + i - mask[word/8] |= 1 << (word % 8) - } - } - } + emitGCMask(mask, base, ktyp, bucketSize) } base += bucketSize * ktyp.size / ptrSize if etyp.ptrdata != 0 { - if etyp.kind&kindGCProg != 0 { - panic("reflect: unexpected GC program in MapOf") - } - emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata)) - for i := uintptr(0); i < etyp.ptrdata/ptrSize; i++ { - if (emask[i/8]>>(i%8))&1 != 0 { - for j := uintptr(0); j < bucketSize; j++ { - word := base + j*etyp.size/ptrSize + i - mask[word/8] |= 1 << (word % 8) - } - } - } + emitGCMask(mask, base, etyp, bucketSize) } base += bucketSize * etyp.size / ptrSize base += overflowPad / ptrSize @@ -2236,6 +2214,55 @@ func bucketOf(ktyp, etyp *rtype) *rtype { return b } +func (t *rtype) gcSlice(begin, end uintptr) []byte { + return (*[1 << 30]byte)(unsafe.Pointer(t.gcdata))[begin:end:end] +} + +// emitGCMask writes the GC mask for [n]typ into out, starting at bit +// offset base. +func emitGCMask(out []byte, base uintptr, typ *rtype, n uintptr) { + if typ.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program") + } + ptrs := typ.ptrdata / ptrSize + words := typ.size / ptrSize + mask := typ.gcSlice(0, (ptrs+7)/8) + for j := uintptr(0); j < ptrs; j++ { + if (mask[j/8]>>(j%8))&1 != 0 { + for i := uintptr(0); i < n; i++ { + k := base + i*words + j + out[k/8] |= 1 << (k % 8) + } + } + } +} + +// appendGCProg appends the GC program for the first ptrdata bytes of +// typ to dst and returns the extended slice. +func appendGCProg(dst []byte, typ *rtype) []byte { + if typ.kind&kindGCProg != 0 { + // Element has GC program; emit one element. + n := uintptr(*(*uint32)(unsafe.Pointer(typ.gcdata))) + prog := typ.gcSlice(4, 4+n-1) + return append(dst, prog...) + } + + // Element is small with pointer mask; use as literal bits. + ptrs := typ.ptrdata / ptrSize + mask := typ.gcSlice(0, (ptrs+7)/8) + + // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). + for ; ptrs > 120; ptrs -= 120 { + dst = append(dst, 120) + dst = append(dst, mask[:15]...) + mask = mask[15:] + } + + dst = append(dst, byte(ptrs)) + dst = append(dst, mask...) + return dst +} + // SliceOf returns the slice type with element type t. // For example, if t represents int, SliceOf(t) represents []int. func SliceOf(t Type) Type { @@ -2666,25 +2693,7 @@ func StructOf(fields []StructField) Type { off = ft.offset() } - elemGC := (*[1 << 30]byte)(unsafe.Pointer(ft.typ.gcdata))[:] - elemPtrs := ft.typ.ptrdata / ptrSize - if ft.typ.kind&kindGCProg == 0 { - // Element is small with pointer mask; use as literal bits. - mask := elemGC - // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). - var n uintptr - for n = elemPtrs; n > 120; n -= 120 { - prog = append(prog, 120) - prog = append(prog, mask[:15]...) - mask = mask[15:] - } - prog = append(prog, byte(n)) - prog = append(prog, mask[:(n+7)/8]...) - } else { - // Element has GC program; emit one element. - elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1] - prog = append(prog, elemProg...) - } + prog = appendGCProg(prog, ft.typ) off += ft.typ.ptrdata } prog = append(prog, 0) @@ -2850,42 +2859,16 @@ func ArrayOf(count int, elem Type) Type { // Create direct pointer mask by turning each 1 bit in elem // into count 1 bits in larger mask. mask := make([]byte, (array.ptrdata/ptrSize+7)/8) - elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] - elemWords := typ.size / ptrSize - for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ { - if (elemMask[j/8]>>(j%8))&1 != 0 { - for i := uintptr(0); i < array.len; i++ { - k := i*elemWords + j - mask[k/8] |= 1 << (k % 8) - } - } - } + emitGCMask(mask, 0, typ, array.len) array.gcdata = &mask[0] default: // Create program that emits one element // and then repeats to make the array. prog := []byte{0, 0, 0, 0} // will be length of prog - elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:] - elemPtrs := typ.ptrdata / ptrSize - if typ.kind&kindGCProg == 0 { - // Element is small with pointer mask; use as literal bits. - mask := elemGC - // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes). - var n uintptr - for n = elemPtrs; n > 120; n -= 120 { - prog = append(prog, 120) - prog = append(prog, mask[:15]...) - mask = mask[15:] - } - prog = append(prog, byte(n)) - prog = append(prog, mask[:(n+7)/8]...) - } else { - // Element has GC program; emit one element. - elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1] - prog = append(prog, elemProg...) - } + prog = appendGCProg(prog, typ) // Pad from ptrdata to size. + elemPtrs := typ.ptrdata / ptrSize elemWords := typ.size / ptrSize if elemPtrs < elemWords { // Emit literal 0 bit, then repeat as needed. |