Fix a bug that crashes in parallel execution

This commit is contained in:
Masaaki Goshima 2020-05-31 00:11:50 +09:00
parent 43a7bdedaa
commit 48b2c82759
1 changed files with 33 additions and 20 deletions

View File

@ -13,6 +13,15 @@ type sliceDecoder struct {
arrayPool sync.Pool arrayPool sync.Pool
} }
// If use reflect.SliceHeader, data type is uintptr.
// In this case, Go compiler cannot trace reference created by newArray().
// So, define using unsafe.Pointer as data type
type sliceHeader struct {
data unsafe.Pointer
len int
cap int
}
func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder { func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder {
return &sliceDecoder{ return &sliceDecoder{
valueDecoder: dec, valueDecoder: dec,
@ -21,23 +30,23 @@ func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder {
arrayPool: sync.Pool{ arrayPool: sync.Pool{
New: func() interface{} { New: func() interface{} {
cap := 2 cap := 2
return &reflect.SliceHeader{ return &sliceHeader{
Data: uintptr(newArray(elemType, cap)), data: newArray(elemType, cap),
Len: 0, len: 0,
Cap: cap, cap: cap,
} }
}, },
}, },
} }
} }
func (d *sliceDecoder) newSlice() *reflect.SliceHeader { func (d *sliceDecoder) newSlice() *sliceHeader {
slice := d.arrayPool.Get().(*reflect.SliceHeader) slice := d.arrayPool.Get().(*sliceHeader)
slice.Len = 0 slice.len = 0
return slice return slice
} }
func (d *sliceDecoder) releaseSlice(p *reflect.SliceHeader) { func (d *sliceDecoder) releaseSlice(p *sliceHeader) {
d.arrayPool.Put(p) d.arrayPool.Put(p)
} }
@ -56,18 +65,18 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
case '[': case '[':
idx := 0 idx := 0
slice := d.newSlice() slice := d.newSlice()
cap := slice.Cap cap := slice.cap
data := slice.Data data := slice.data
for { for {
cursor++ cursor++
if cap <= idx { if cap <= idx {
src := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} src := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
cap *= 2 cap *= 2
data = uintptr(newArray(d.elemType, cap)) data = newArray(d.elemType, cap)
dst := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} dst := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap}
copySlice(d.elemType, dst, src) copySlice(d.elemType, dst, src)
} }
c, err := d.valueDecoder.decode(buf, cursor, data+uintptr(idx)*d.size) c, err := d.valueDecoder.decode(buf, cursor, uintptr(data)+uintptr(idx)*d.size)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -75,16 +84,20 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
cursor = skipWhiteSpace(buf, cursor) cursor = skipWhiteSpace(buf, cursor)
switch buf[cursor] { switch buf[cursor] {
case ']': case ']':
slice.Cap = cap slice.cap = cap
slice.Len = idx + 1 slice.len = idx + 1
slice.Data = data slice.data = data
dstCap := idx + 1 dstCap := idx + 1
dst := reflect.SliceHeader{ dst := reflect.SliceHeader{
Data: uintptr(newArray(d.elemType, dstCap)), Data: uintptr(newArray(d.elemType, dstCap)),
Len: idx + 1, Len: idx + 1,
Cap: dstCap, Cap: dstCap,
} }
copySlice(d.elemType, dst, *slice) copySlice(d.elemType, dst, reflect.SliceHeader{
Data: uintptr(slice.data),
Len: slice.len,
Cap: slice.cap,
})
*(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst *(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst
d.releaseSlice(slice) d.releaseSlice(slice)
cursor++ cursor++
@ -93,8 +106,8 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error
idx++ idx++
continue continue
default: default:
slice.Cap = cap slice.cap = cap
slice.Data = data slice.data = data
d.releaseSlice(slice) d.releaseSlice(slice)
return 0, errInvalidCharacter(buf[cursor], "slice", cursor) return 0, errInvalidCharacter(buf[cursor], "slice", cursor)
} }