]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: better handle arrays whose length expression is invalid
authorRobert Griesemer <gri@golang.org>
Tue, 13 Feb 2018 00:42:31 +0000 (16:42 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 13 Feb 2018 20:31:05 +0000 (20:31 +0000)
While doing that, establish a negative value as signal for unknown
array lengths and adjust various array-length processing code to
handle that case.

Fixes #23712.

Change-Id: Icf488faaf972638b42b22d4b4607d1c512c8fc2c
Reviewed-on: https://go-review.googlesource.com/93438
Reviewed-by: Alan Donovan <adonovan@google.com>
src/go/types/builtins.go
src/go/types/predicates.go
src/go/types/sizes.go
src/go/types/testdata/importC.src
src/go/types/type.go
src/go/types/typexpr.go

index f22851e240ecef431c09624d0e80c683c9fe31f1..785daec331a0942b6f36c7363d59d3b8992f782d 100644 (file)
@@ -158,7 +158,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        // function calls; in this case s is not evaluated."
                        if !check.hasCallOrRecv {
                                mode = constant_
-                               val = constant.MakeInt64(t.len)
+                               if t.len >= 0 {
+                                       val = constant.MakeInt64(t.len)
+                               } else {
+                                       val = constant.MakeUnknown()
+                               }
                        }
 
                case *Slice, *Chan:
index 3aa4878cce25fbdfb147f1af29a621487460ceba..1ca146f59049b778f5b46e787a750c86204953e7 100644 (file)
@@ -150,7 +150,9 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
                // Two array types are identical if they have identical element types
                // and the same array length.
                if y, ok := y.(*Array); ok {
-                       return x.len == y.len && identical(x.elem, y.elem, cmpTags, p)
+                       // If one or both array lengths are unknown (< 0) due to some error,
+                       // assume they are the same to avoid spurious follow-on errors.
+                       return (x.len < 0 || y.len < 0 || x.len == y.len) && identical(x.elem, y.elem, cmpTags, p)
                }
 
        case *Slice:
index 0821a61359d7a055fa130afe8f7c439a19114306..eb274799f42e96c6024ebf6b4ef311705ea5f0e4 100644 (file)
@@ -132,9 +132,10 @@ func (s *StdSizes) Sizeof(T Type) int64 {
                }
        case *Array:
                n := t.len
-               if n == 0 {
+               if n <= 0 {
                        return 0
                }
+               // n > 0
                a := s.Alignof(t.elem)
                z := s.Sizeof(t.elem)
                return align(z, a)*(n-1) + z
index f50f7f33d3e8648da277c37adf9f96bc3290d833..f55be2d5c53c89ca57076da9755e2019d6b55d1b 100644 (file)
@@ -20,7 +20,7 @@ type T struct {
        Ordinal int
 }
 
-func f(args []T) {
+func _(args []T) {
        var s string
        for i, v := range args {
                cname := C.CString(v.Name)
@@ -33,3 +33,22 @@ type CType C.Type
 
 const _ CType = C.X // no error due to invalid constant type
 const _ = C.X
+
+// Test cases extracted from issue #23712.
+
+func _() {
+       var a [C.ArrayLength]byte
+       _ = a[0] // no index out of bounds error here
+}
+
+// Additional tests to verify fix for #23712.
+
+func _() {
+       var a [C.ArrayLength1]byte
+       _ = 1 / len(a) // no division by zero error here and below
+       _ = 1 / cap(a)
+       _ = uint(unsafe.Sizeof(a)) // must not be negative
+
+       var b [C.ArrayLength2]byte
+       a = b // should be valid
+}
index 50e3c6e4d0557c77fa994f9559878c805f2e53b8..afdbb680f830dd1f6febf45959542bf3d27b2084 100644 (file)
@@ -97,9 +97,11 @@ type Array struct {
 }
 
 // NewArray returns a new array type for the given element type and length.
+// A negative length indicates an unknown length.
 func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
 
 // Len returns the length of array a.
+// A negative result indicates an unknown length.
 func (a *Array) Len() int64 { return a.len }
 
 // Elem returns element type of array a.
index aedd71e9186e4d498bbab90427b9510630500325..e86834efdd24b585858ef185a90151f74349bc24 100644 (file)
@@ -380,6 +380,9 @@ func (check *Checker) typOrNil(e ast.Expr) Type {
        return Typ[Invalid]
 }
 
+// arrayLength type-checks the array length expression e
+// and returns the constant length >= 0, or a value < 0
+// to indicate an error (and thus an unknown length).
 func (check *Checker) arrayLength(e ast.Expr) int64 {
        var x operand
        check.expr(&x, e)
@@ -387,7 +390,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
                if x.mode != invalid {
                        check.errorf(x.pos(), "array length %s must be constant", &x)
                }
-               return 0
+               return -1
        }
        if isUntyped(x.typ) || isInteger(x.typ) {
                if val := constant.ToInt(x.val); val.Kind() == constant.Int {
@@ -396,12 +399,12 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
                                        return n
                                }
                                check.errorf(x.pos(), "invalid array length %s", &x)
-                               return 0
+                               return -1
                        }
                }
        }
        check.errorf(x.pos(), "array length %s must be integer", &x)
-       return 0
+       return -1
 }
 
 func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {