Commit 7f1bc533 authored by Alberto Donizetti's avatar Alberto Donizetti Committed by Robert Griesemer

cmd/compile: only allow integer expressions as keys in array literals

Fixes #16439
Updates #16679

Change-Id: Idff4b313f29351866b1a649786501adee85fd580
Reviewed-on: https://go-review.googlesource.com/29011
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent c2735039
...@@ -1513,37 +1513,33 @@ func smallintconst(n *Node) bool { ...@@ -1513,37 +1513,33 @@ func smallintconst(n *Node) bool {
return true return true
case TIDEAL, TINT64, TUINT64, TPTR64: case TIDEAL, TINT64, TUINT64, TPTR64:
if n.Val().U.(*Mpint).Cmp(minintval[TINT32]) < 0 || n.Val().U.(*Mpint).Cmp(maxintval[TINT32]) > 0 { v, ok := n.Val().U.(*Mpint)
break if ok && v.Cmp(minintval[TINT32]) > 0 && v.Cmp(maxintval[TINT32]) < 0 {
return true
} }
return true
} }
} }
return false return false
} }
func nonnegconst(n *Node) int { // nonnegintconst checks if Node n contains a constant expression
if n.Op == OLITERAL && n.Type != nil { // representable as a non-negative small integer, and returns its
switch simtype[n.Type.Etype] { // (integer) value if that's the case. Otherwise, it returns -1.
// check negative and 2^31 func nonnegintconst(n *Node) int64 {
case TINT8, if n.Op != OLITERAL {
TUINT8, return -1
TINT16, }
TUINT16,
TINT32, // toint will leave n.Val unchanged if it's not castable to an
TUINT32, // Mpint, so we still have to guard the conversion.
TINT64, v := toint(n.Val())
TUINT64, vi, ok := v.U.(*Mpint)
TIDEAL: if !ok || vi.Val.Sign() < 0 || vi.Cmp(maxintval[TINT32]) > 0 {
if n.Val().U.(*Mpint).Cmp(minintval[TUINT32]) < 0 || n.Val().U.(*Mpint).Cmp(maxintval[TINT32]) > 0 { return -1
break
}
return int(n.Int64())
}
} }
return -1 return vi.Int64()
} }
// convert x to type et and back to int64 // convert x to type et and back to int64
......
...@@ -1226,10 +1226,11 @@ func initplan(n *Node) { ...@@ -1226,10 +1226,11 @@ func initplan(n *Node) {
case OARRAYLIT, OSLICELIT: case OARRAYLIT, OSLICELIT:
for _, a := range n.List.Slice() { for _, a := range n.List.Slice() {
if a.Op != OKEY || !smallintconst(a.Left) { index := nonnegintconst(a.Left)
if a.Op != OKEY || index < 0 {
Fatalf("initplan fixedlit") Fatalf("initplan fixedlit")
} }
addvalue(p, n.Type.Elem().Width*a.Left.Int64(), a.Right) addvalue(p, index*n.Type.Elem().Width, a.Right)
} }
case OSTRUCTLIT: case OSTRUCTLIT:
......
...@@ -2781,19 +2781,6 @@ func keydup(n *Node, hash map[uint32][]*Node) { ...@@ -2781,19 +2781,6 @@ func keydup(n *Node, hash map[uint32][]*Node) {
hash[h] = append(hash[h], orign) hash[h] = append(hash[h], orign)
} }
func indexdup(n *Node, hash map[int64]*Node) {
if n.Op != OLITERAL {
Fatalf("indexdup: not OLITERAL")
}
v := n.Int64()
if hash[v] != nil {
yyerror("duplicate index in array literal: %d", v)
return
}
hash[v] = n
}
// iscomptype reports whether type t is a composite literal type // iscomptype reports whether type t is a composite literal type
// or a pointer to one. // or a pointer to one.
func iscomptype(t *Type) bool { func iscomptype(t *Type) bool {
...@@ -2890,16 +2877,17 @@ func typecheckcomplit(n *Node) *Node { ...@@ -2890,16 +2877,17 @@ func typecheckcomplit(n *Node) *Node {
n.Type = nil n.Type = nil
case TARRAY, TSLICE: case TARRAY, TSLICE:
// Only allocate hash if there are some key/value pairs. // If there are key/value pairs, create a map to keep seen
var hash map[int64]*Node // keys so we can check for duplicate indices.
var indices map[int64]bool
for _, n1 := range n.List.Slice() { for _, n1 := range n.List.Slice() {
if n1.Op == OKEY { if n1.Op == OKEY {
hash = make(map[int64]*Node) indices = make(map[int64]bool)
break break
} }
} }
length := int64(0)
i := 0 var length, i int64
checkBounds := t.IsArray() && !t.isDDDArray() checkBounds := t.IsArray() && !t.isDDDArray()
for i2, n2 := range n.List.Slice() { for i2, n2 := range n.List.Slice() {
l := n2 l := n2
...@@ -2913,19 +2901,25 @@ func typecheckcomplit(n *Node) *Node { ...@@ -2913,19 +2901,25 @@ func typecheckcomplit(n *Node) *Node {
l.Left = typecheck(l.Left, Erv) l.Left = typecheck(l.Left, Erv)
evconst(l.Left) evconst(l.Left)
i = nonnegconst(l.Left)
i = nonnegintconst(l.Left)
if i < 0 && l.Left.Diag == 0 { if i < 0 && l.Left.Diag == 0 {
yyerror("index must be non-negative integer constant") yyerror("index must be non-negative integer constant")
l.Left.Diag = 1 l.Left.Diag = 1
i = -(1 << 30) // stay negative for a while i = -(1 << 30) // stay negative for a while
} }
if i >= 0 && hash != nil { if i >= 0 && indices != nil {
indexdup(l.Left, hash) if indices[i] {
yyerror("duplicate index in array literal: %d", i)
} else {
indices[i] = true
}
} }
i++ i++
if int64(i) > length { if i > length {
length = int64(i) length = i
if checkBounds && length > t.NumElem() { if checkBounds && length > t.NumElem() {
setlineno(l) setlineno(l)
yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem()) yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
......
// errorcheck
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
var a []int = []int{1: 1}
var b []int = []int{-1: 1} // ERROR "must be non-negative integer constant"
var c []int = []int{2.0: 2}
var d []int = []int{-2.0: 2} // ERROR "must be non-negative integer constant"
var e []int = []int{3 + 0i: 3}
var f []int = []int{3i: 3} // ERROR "truncated to real"
var g []int = []int{"a": 4} // ERROR "must be non-negative integer constant"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment