From 3810fa8296bd35d6bc1a354d837a84ea032a7672 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 22 Jul 2021 10:42:02 +0700 Subject: [PATCH] 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 Trust: Tim King Run-TryBot: Cuong Manh Le Run-TryBot: Tim King gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Tim King Reviewed-by: Bryan C. Mills --- go/ssa/interp/ops.go | 10 +++-- go/ssa/interp/testdata/slice2arrayptr.go | 53 +++++++++++++++++------- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/go/ssa/interp/ops.go b/go/ssa/interp/ops.go index 9c12d4a66c..6af7847c03 100644 --- a/go/ssa/interp/ops.go +++ b/go/ssa/interp/ops.go @@ -1367,11 +1367,13 @@ func sliceToArrayPointer(t_dst, t_src types.Type, x value) value { 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 21f990624b..ad37a18409 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() }