go/ssa/interp: handle nil slice convert to array pointer
Converting from nil slice to a zero length array pointer must be nil.
Updates golang/go#46987
Change-Id: I8894b92bd85fae8ea77bf01b92ee56f1a215a75b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/336489
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Tim King <taking@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go
index 9c12d4a..6af7847 100644
--- a/go/ssa/interp/ops.go
+++ b/go/ssa/interp/ops.go
@@ -1367,11 +1367,13 @@
if utSrc, ok := utDst.(*types.Pointer); ok {
if arr, ok := utSrc.Elem().(*types.Array); ok {
x := x.([]value)
- a := make(array, arr.Len())
- for i := range a {
- a[i] = x[i]
+ if arr.Len() > int64(len(x)) {
+ panic("array length is greater than slice length")
}
- v := value(a)
+ if x == nil {
+ return zero(utSrc)
+ }
+ v := value(array(x[:arr.Len()]))
return &v
}
}
diff --git a/go/ssa/interp/testdata/slice2arrayptr.go b/go/ssa/interp/testdata/slice2arrayptr.go
index 21f9906..ad37a18 100644
--- a/go/ssa/interp/testdata/slice2arrayptr.go
+++ b/go/ssa/interp/testdata/slice2arrayptr.go
@@ -2,22 +2,47 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Test for slice to array pointer conversion introduced in go1.17
+// See: https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
+
package main
-// Test for slice to array pointer conversion introduced in go1.17
-
-import "fmt"
-
-var s = []byte{1, 2, 3, 4}
-var a = (*[4]byte)(s)
-
func main() {
- for i := range s {
- if a[i] != s[i] {
- panic(fmt.Sprintf("value mismatched: %v - %v\n", a[i], s[i]))
- }
- if (*a)[i] != s[i] {
- panic(fmt.Sprintf("value mismatched: %v - %v\n", (*a)[i], s[i]))
- }
+ s := make([]byte, 2, 4)
+ if s0 := (*[0]byte)(s); s0 == nil {
+ panic("converted from non-nil slice result in nil array pointer")
}
+ if s2 := (*[2]byte)(s); &s2[0] != &s[0] {
+ panic("the converted array is not slice underlying array")
+ }
+ wantPanic(
+ func() {
+ _ = (*[4]byte)(s) // panics: len([4]byte) > len(s)
+ },
+ "runtime error: array length is greater than slice length",
+ )
+
+ var t []string
+ if t0 := (*[0]string)(t); t0 != nil {
+ panic("nil slice converted to *[0]byte should be nil")
+ }
+ wantPanic(
+ func() {
+ _ = (*[1]string)(t) // panics: len([1]string) > len(t)
+ },
+ "runtime error: array length is greater than slice length",
+ )
+}
+
+func wantPanic(fn func(), s string) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("expected panic")
+ }
+ if got := err.(error).Error(); got != s {
+ panic("expected panic " + s + " got " + got)
+ }
+ }()
+ fn()
}