mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: panic if ArrayOf is called with negative length
Since we cannot change the signature of reflect.ArrayOf to return an error, we panic instead of producing a wrong result. Fixes #43603 Change-Id: I23915df8d190f35af4d00ab86768868cd621e839 Reviewed-on: https://go-review.googlesource.com/c/go/+/284136 Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
661f3f15d5
commit
d7cc2f1d7c
2 changed files with 30 additions and 18 deletions
|
|
@ -4636,6 +4636,14 @@ func TestArrayOfDirectIface(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure passing in negative lengths panics.
|
||||||
|
// See https://golang.org/issue/43603
|
||||||
|
func TestArrayOfPanicOnNegativeLength(t *testing.T) {
|
||||||
|
shouldPanic("reflect: negative length passed to ArrayOf", func() {
|
||||||
|
ArrayOf(-1, TypeOf(byte(0)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestSliceOf(t *testing.T) {
|
func TestSliceOf(t *testing.T) {
|
||||||
// check construction and use of type not in binary
|
// check construction and use of type not in binary
|
||||||
type T int
|
type T int
|
||||||
|
|
|
||||||
|
|
@ -2835,22 +2835,26 @@ func typeptrdata(t *rtype) uintptr {
|
||||||
// See cmd/compile/internal/gc/reflect.go for derivation of constant.
|
// See cmd/compile/internal/gc/reflect.go for derivation of constant.
|
||||||
const maxPtrmaskBytes = 2048
|
const maxPtrmaskBytes = 2048
|
||||||
|
|
||||||
// ArrayOf returns the array type with the given count and element type.
|
// ArrayOf returns the array type with the given length and element type.
|
||||||
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
|
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
|
||||||
//
|
//
|
||||||
// If the resulting type would be larger than the available address space,
|
// If the resulting type would be larger than the available address space,
|
||||||
// ArrayOf panics.
|
// ArrayOf panics.
|
||||||
func ArrayOf(count int, elem Type) Type {
|
func ArrayOf(length int, elem Type) Type {
|
||||||
|
if length < 0 {
|
||||||
|
panic("reflect: negative length passed to ArrayOf")
|
||||||
|
}
|
||||||
|
|
||||||
typ := elem.(*rtype)
|
typ := elem.(*rtype)
|
||||||
|
|
||||||
// Look in cache.
|
// Look in cache.
|
||||||
ckey := cacheKey{Array, typ, nil, uintptr(count)}
|
ckey := cacheKey{Array, typ, nil, uintptr(length)}
|
||||||
if array, ok := lookupCache.Load(ckey); ok {
|
if array, ok := lookupCache.Load(ckey); ok {
|
||||||
return array.(Type)
|
return array.(Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look in known types.
|
// Look in known types.
|
||||||
s := "[" + strconv.Itoa(count) + "]" + typ.String()
|
s := "[" + strconv.Itoa(length) + "]" + typ.String()
|
||||||
for _, tt := range typesByString(s) {
|
for _, tt := range typesByString(s) {
|
||||||
array := (*arrayType)(unsafe.Pointer(tt))
|
array := (*arrayType)(unsafe.Pointer(tt))
|
||||||
if array.elem == typ {
|
if array.elem == typ {
|
||||||
|
|
@ -2866,7 +2870,7 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
array.tflag = typ.tflag & tflagRegularMemory
|
array.tflag = typ.tflag & tflagRegularMemory
|
||||||
array.str = resolveReflectName(newName(s, "", false))
|
array.str = resolveReflectName(newName(s, "", false))
|
||||||
array.hash = fnv1(typ.hash, '[')
|
array.hash = fnv1(typ.hash, '[')
|
||||||
for n := uint32(count); n > 0; n >>= 8 {
|
for n := uint32(length); n > 0; n >>= 8 {
|
||||||
array.hash = fnv1(array.hash, byte(n))
|
array.hash = fnv1(array.hash, byte(n))
|
||||||
}
|
}
|
||||||
array.hash = fnv1(array.hash, ']')
|
array.hash = fnv1(array.hash, ']')
|
||||||
|
|
@ -2874,17 +2878,17 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
array.ptrToThis = 0
|
array.ptrToThis = 0
|
||||||
if typ.size > 0 {
|
if typ.size > 0 {
|
||||||
max := ^uintptr(0) / typ.size
|
max := ^uintptr(0) / typ.size
|
||||||
if uintptr(count) > max {
|
if uintptr(length) > max {
|
||||||
panic("reflect.ArrayOf: array size would exceed virtual address space")
|
panic("reflect.ArrayOf: array size would exceed virtual address space")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array.size = typ.size * uintptr(count)
|
array.size = typ.size * uintptr(length)
|
||||||
if count > 0 && typ.ptrdata != 0 {
|
if length > 0 && typ.ptrdata != 0 {
|
||||||
array.ptrdata = typ.size*uintptr(count-1) + typ.ptrdata
|
array.ptrdata = typ.size*uintptr(length-1) + typ.ptrdata
|
||||||
}
|
}
|
||||||
array.align = typ.align
|
array.align = typ.align
|
||||||
array.fieldAlign = typ.fieldAlign
|
array.fieldAlign = typ.fieldAlign
|
||||||
array.len = uintptr(count)
|
array.len = uintptr(length)
|
||||||
array.slice = SliceOf(elem).(*rtype)
|
array.slice = SliceOf(elem).(*rtype)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -2893,7 +2897,7 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
array.gcdata = nil
|
array.gcdata = nil
|
||||||
array.ptrdata = 0
|
array.ptrdata = 0
|
||||||
|
|
||||||
case count == 1:
|
case length == 1:
|
||||||
// In memory, 1-element array looks just like the element.
|
// In memory, 1-element array looks just like the element.
|
||||||
array.kind |= typ.kind & kindGCProg
|
array.kind |= typ.kind & kindGCProg
|
||||||
array.gcdata = typ.gcdata
|
array.gcdata = typ.gcdata
|
||||||
|
|
@ -2902,7 +2906,7 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize:
|
case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize:
|
||||||
// Element is small with pointer mask; array is still small.
|
// Element is small with pointer mask; array is still small.
|
||||||
// Create direct pointer mask by turning each 1 bit in elem
|
// Create direct pointer mask by turning each 1 bit in elem
|
||||||
// into count 1 bits in larger mask.
|
// into length 1 bits in larger mask.
|
||||||
mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
|
mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
|
||||||
emitGCMask(mask, 0, typ, array.len)
|
emitGCMask(mask, 0, typ, array.len)
|
||||||
array.gcdata = &mask[0]
|
array.gcdata = &mask[0]
|
||||||
|
|
@ -2923,14 +2927,14 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
prog = appendVarint(prog, elemWords-elemPtrs-1)
|
prog = appendVarint(prog, elemWords-elemPtrs-1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Repeat count-1 times.
|
// Repeat length-1 times.
|
||||||
if elemWords < 0x80 {
|
if elemWords < 0x80 {
|
||||||
prog = append(prog, byte(elemWords|0x80))
|
prog = append(prog, byte(elemWords|0x80))
|
||||||
} else {
|
} else {
|
||||||
prog = append(prog, 0x80)
|
prog = append(prog, 0x80)
|
||||||
prog = appendVarint(prog, elemWords)
|
prog = appendVarint(prog, elemWords)
|
||||||
}
|
}
|
||||||
prog = appendVarint(prog, uintptr(count)-1)
|
prog = appendVarint(prog, uintptr(length)-1)
|
||||||
prog = append(prog, 0)
|
prog = append(prog, 0)
|
||||||
*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
|
*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
|
||||||
array.kind |= kindGCProg
|
array.kind |= kindGCProg
|
||||||
|
|
@ -2944,9 +2948,9 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
array.equal = nil
|
array.equal = nil
|
||||||
if eequal := etyp.equal; eequal != nil {
|
if eequal := etyp.equal; eequal != nil {
|
||||||
array.equal = func(p, q unsafe.Pointer) bool {
|
array.equal = func(p, q unsafe.Pointer) bool {
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < length; i++ {
|
||||||
pi := arrayAt(p, i, esize, "i < count")
|
pi := arrayAt(p, i, esize, "i < length")
|
||||||
qi := arrayAt(q, i, esize, "i < count")
|
qi := arrayAt(q, i, esize, "i < length")
|
||||||
if !eequal(pi, qi) {
|
if !eequal(pi, qi) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -2957,7 +2961,7 @@ func ArrayOf(count int, elem Type) Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case count == 1 && !ifaceIndir(typ):
|
case length == 1 && !ifaceIndir(typ):
|
||||||
// array of 1 direct iface type can be direct
|
// array of 1 direct iface type can be direct
|
||||||
array.kind |= kindDirectIface
|
array.kind |= kindDirectIface
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue