Remove all usages of reflect.SliceHeader

There're some problem with current usage of reflect.SliceHeader.

First, it violates the unsafe pointer conversion (rule 6th), that said,
reflect.SliceHeader must not used as plain struct.

Second, the lowest version that go-json supports, go1.12, reflect
package did not use SliceHeader in typedslicecopy, but use the safety
version. There's no reason that go-json continue using them.

See:

 - https://golang.org/pkg/unsafe/#Pointer
 - https://github.com/golang/go/blob/release-branch.go1.12/src/reflect/value.go#L2702
This commit is contained in:
Cuong Manh Le 2020-11-15 01:24:34 +07:00
parent 71cddb3168
commit e58b1eabaf
No known key found for this signature in database
GPG Key ID: C3FA65829435642E
3 changed files with 63 additions and 65 deletions

View File

@ -1,7 +1,6 @@
package json
import (
"reflect"
"sync"
"unsafe"
)
@ -51,7 +50,7 @@ func (d *sliceDecoder) releaseSlice(p *sliceHeader) {
}
//go:linkname copySlice reflect.typedslicecopy
func copySlice(elemType *rtype, dst, src reflect.SliceHeader) int
func copySlice(elemType *rtype, dst, src sliceHeader) int
//go:linkname newArray reflect.unsafe_NewArray
func newArray(*rtype, int) unsafe.Pointer
@ -71,10 +70,10 @@ func (d *sliceDecoder) decodeStream(s *stream, p uintptr) error {
s.cursor++
s.skipWhiteSpace()
if s.char() == ']' {
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = reflect.SliceHeader{
Data: uintptr(newArray(d.elemType, 0)),
Len: 0,
Cap: 0,
*(*sliceHeader)(unsafe.Pointer(p)) = sliceHeader{
data: newArray(d.elemType, 0),
len: 0,
cap: 0,
}
s.cursor++
return nil
@ -85,10 +84,10 @@ func (d *sliceDecoder) decodeStream(s *stream, p uintptr) error {
data := slice.data
for {
if cap <= idx {
src := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
src := sliceHeader{data: data, len: idx, cap: cap}
cap *= 2
data = newArray(d.elemType, cap)
dst := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
dst := sliceHeader{data: data, len: idx, cap: cap}
copySlice(d.elemType, dst, src)
}
if err := d.valueDecoder.decodeStream(s, uintptr(data)+uintptr(idx)*d.size); err != nil {
@ -102,17 +101,17 @@ func (d *sliceDecoder) decodeStream(s *stream, p uintptr) error {
slice.len = idx + 1
slice.data = data
dstCap := idx + 1
dst := reflect.SliceHeader{
Data: uintptr(newArray(d.elemType, dstCap)),
Len: idx + 1,
Cap: dstCap,
dst := sliceHeader{
data: newArray(d.elemType, dstCap),
len: idx + 1,
cap: dstCap,
}
copySlice(d.elemType, dst, reflect.SliceHeader{
Data: uintptr(slice.data),
Len: slice.len,
Cap: slice.cap,
copySlice(d.elemType, dst, sliceHeader{
data: slice.data,
len: slice.len,
cap: slice.cap,
})
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst
*(*sliceHeader)(unsafe.Pointer(p)) = dst
d.releaseSlice(slice)
s.cursor++
return nil
@ -171,10 +170,10 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
cursor++
cursor = skipWhiteSpace(buf, cursor)
if buf[cursor] == ']' {
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = reflect.SliceHeader{
Data: uintptr(newArray(d.elemType, 0)),
Len: 0,
Cap: 0,
*(*sliceHeader)(unsafe.Pointer(p)) = sliceHeader{
data: newArray(d.elemType, 0),
len: 0,
cap: 0,
}
cursor++
return cursor, nil
@ -185,10 +184,10 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
data := slice.data
for {
if cap <= idx {
src := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
src := sliceHeader{data: data, len: idx, cap: cap}
cap *= 2
data = newArray(d.elemType, cap)
dst := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
dst := sliceHeader{data: data, len: idx, cap: cap}
copySlice(d.elemType, dst, src)
}
c, err := d.valueDecoder.decode(buf, cursor, uintptr(data)+uintptr(idx)*d.size)
@ -203,17 +202,17 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
slice.len = idx + 1
slice.data = data
dstCap := idx + 1
dst := reflect.SliceHeader{
Data: uintptr(newArray(d.elemType, dstCap)),
Len: idx + 1,
Cap: dstCap,
dst := sliceHeader{
data: newArray(d.elemType, dstCap),
len: idx + 1,
cap: dstCap,
}
copySlice(d.elemType, dst, reflect.SliceHeader{
Data: uintptr(slice.data),
Len: slice.len,
Cap: slice.cap,
copySlice(d.elemType, dst, sliceHeader{
data: slice.data,
len: slice.len,
cap: slice.cap,
})
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst
*(*sliceHeader)(unsafe.Pointer(p)) = dst
d.releaseSlice(slice)
cursor++
return cursor, nil

View File

@ -1,7 +1,6 @@
package json
import (
"reflect"
"unsafe"
)
@ -95,6 +94,6 @@ func (c *encodeRuntimeContext) init(p uintptr) {
}
func (c *encodeRuntimeContext) ptr() uintptr {
header := (*reflect.SliceHeader)(unsafe.Pointer(&c.ptrs))
return header.Data
header := (*sliceHeader)(unsafe.Pointer(&c.ptrs))
return uintptr(header.data)
}

View File

@ -175,8 +175,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
code = code.next
case opBytes:
ptr := load(ctxptr, code.idx)
header := (*reflect.SliceHeader)(unsafe.Pointer(ptr))
if ptr == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(ptr))
if ptr == 0 || uintptr(header.data) == 0 {
e.encodeNull()
} else {
e.encodeByteSlice(e.ptrToBytes(ptr))
@ -498,19 +498,19 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
code = code.next
case opSliceHead:
p := load(ctxptr, code.idx)
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
e.encodeNull()
e.encodeByte(',')
code = code.end.next
} else {
store(ctxptr, code.elemIdx, 0)
store(ctxptr, code.length, uintptr(header.Len))
store(ctxptr, code.idx, header.Data)
if header.Len > 0 {
store(ctxptr, code.length, uintptr(header.len))
store(ctxptr, code.idx, uintptr(header.data))
if header.len > 0 {
e.encodeByte('[')
code = code.next
store(ctxptr, code.idx, header.Data)
store(ctxptr, code.idx, uintptr(header.data))
} else {
e.encodeBytes([]byte{'[', ']', ','})
code = code.end.next
@ -540,15 +540,15 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
e.encodeBytes([]byte{',', '\n'})
code = code.end.next
} else {
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
header := (*sliceHeader)(unsafe.Pointer(p))
store(ctxptr, code.elemIdx, 0)
store(ctxptr, code.length, uintptr(header.Len))
store(ctxptr, code.idx, header.Data)
if header.Len > 0 {
store(ctxptr, code.length, uintptr(header.len))
store(ctxptr, code.idx, uintptr(header.data))
if header.len > 0 {
e.encodeBytes([]byte{'[', '\n'})
e.encodeIndent(code.indent + 1)
code = code.next
store(ctxptr, code.idx, header.Data)
store(ctxptr, code.idx, uintptr(header.data))
} else {
e.encodeIndent(code.indent)
e.encodeBytes([]byte{'[', ']', '\n'})
@ -563,15 +563,15 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
e.encodeBytes([]byte{',', '\n'})
code = code.end.next
} else {
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
header := (*sliceHeader)(unsafe.Pointer(p))
store(ctxptr, code.elemIdx, 0)
store(ctxptr, code.length, uintptr(header.Len))
store(ctxptr, code.idx, header.Data)
if header.Len > 0 {
store(ctxptr, code.length, uintptr(header.len))
store(ctxptr, code.idx, uintptr(header.data))
if header.len > 0 {
e.encodeBytes([]byte{'[', '\n'})
e.encodeIndent(code.indent + 1)
code = code.next
store(ctxptr, code.idx, header.Data)
store(ctxptr, code.idx, uintptr(header.data))
} else {
e.encodeIndent(code.indent)
e.encodeBytes([]byte{'[', ']', ',', '\n'})
@ -5229,8 +5229,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
e.encodeByte(' ')
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
e.encodeNull()
e.encodeBytes([]byte{',', '\n'})
code = code.nextField
@ -5243,8 +5243,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
e.encodeByte(' ')
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
e.encodeNull()
e.encodeBytes([]byte{',', '\n'})
code = code.nextField
@ -5509,8 +5509,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
case opStructFieldOmitEmptyArray:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
code = code.nextField
} else {
code = code.next
@ -5518,8 +5518,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
case opStructFieldOmitEmptySlice:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
code = code.nextField
} else {
code = code.next
@ -5740,8 +5740,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
case opStructFieldOmitEmptyArrayIndent:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
code = code.nextField
} else {
e.encodeIndent(code.indent)
@ -5752,8 +5752,8 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, code *opcode) error {
case opStructFieldOmitEmptySliceIndent:
ptr := load(ctxptr, code.headIdx)
p := ptr + code.offset
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
if p == 0 || header.Data == 0 {
header := (*sliceHeader)(unsafe.Pointer(p))
if p == 0 || uintptr(header.data) == 0 {
code = code.nextField
} else {
e.encodeIndent(code.indent)