static void stringtoarraylit(Node**);
static Node* resolve(Node*);
static void checkdefergo(Node*);
+static int checkmake(Type*, char*, Node*);
static NodeList* typecheckdefstack;
l = args->n;
args = args->next;
typecheck(&l, Erv);
- defaultlit(&l, types[TINT]);
r = N;
if(args != nil) {
r = args->n;
args = args->next;
typecheck(&r, Erv);
- defaultlit(&r, types[TINT]);
}
if(l->type == T || (r && r->type == T))
goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer len argument to make(%T)", t);
+ et = checkmake(t, "len", l) < 0;
+ et |= r && checkmake(t, "cap", r) < 0;
+ if(et)
goto error;
- }
- if(r && !isint[r->type->etype]) {
- yyerror("non-integer cap argument to make(%T)", t);
+ if(isconst(l, CTINT) && r && isconst(r, CTINT) && mpcmpfixfix(l->val.u.xval, r->val.u.xval) > 0) {
+ yyerror("len larger than cap in make(%T)", t);
goto error;
}
n->left = l;
defaultlit(&l, types[TINT]);
if(l->type == T)
goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer size argument to make(%T)", t);
+ if(checkmake(t, "size", l) < 0)
goto error;
- }
n->left = l;
} else
n->left = nodintconst(0);
defaultlit(&l, types[TINT]);
if(l->type == T)
goto error;
- if(!isint[l->type->etype]) {
- yyerror("non-integer buffer argument to make(%T)", t);
+ if(checkmake(t, "buffer", l) < 0)
goto error;
- }
n->left = l;
} else
n->left = nodintconst(0);
n->walkdef = 1;
return n;
}
+
+static int
+checkmake(Type *t, char *arg, Node *n)
+{
+ if(n->op == OLITERAL) {
+ n->val = toint(n->val);
+ if(mpcmpfixc(n->val.u.xval, 0) < 0) {
+ yyerror("negative %s argument in make(%T)", arg, t);
+ return -1;
+ }
+ if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
+ yyerror("%s argument too large in make(%T)", arg, t);
+ return -1;
+ }
+
+ // Delay defaultlit until after we've checked range, to avoid
+ // a redundant "constant NNN overflows int" error.
+ defaultlit(&n, types[TINT]);
+ return 0;
+ }
+
+ // Defaultlit still necessary for non-constant: n might be 1<<k.
+ defaultlit(&n, types[TINT]);
+
+ if(!isint[n->type->etype]) {
+ yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
+ return -1;
+ }
+ return 0;
+}
void
runtimeĀ·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{
- if(len < 0 || (intgo)len != len)
+ // NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
+ // but it produces a 'len out of range' error instead of a 'cap out of range' error
+ // when someone does make([]T, bignumber). 'cap out of range' is true too,
+ // but since the cap is only being supplied implicitly, saying len is clearer.
+ // See issue 4085.
+ if(len < 0 || (intgo)len != len || t->elem->size > 0 && len > MaxMem / t->elem->size)
runtimeĀ·panicstring("makeslice: len out of range");
-
+
if(cap < len || (intgo)cap != cap || t->elem->size > 0 && cap > MaxMem / t->elem->size)
runtimeĀ·panicstring("makeslice: cap out of range");
--- /dev/null
+// errorcheck
+
+// Copyright 2013 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 main
+
+type T []int
+
+func main() {
+ _ = make(T, -1) // ERROR "negative"
+ _ = make(T, 0.5) // ERROR "constant 0.5 truncated to integer"
+ _ = make(T, 1.0) // ok
+ _ = make(T, 1<<63) // ERROR "len argument too large"
+ _ = make(T, 0, -1) // ERROR "negative cap"
+ _ = make(T, 10, 0) // ERROR "len larger than cap"
+}
--- /dev/null
+// run
+
+// Copyright 2013 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 main
+
+import (
+ "strings"
+ "unsafe"
+)
+
+type T []int
+
+func main() {
+ n := -1
+ shouldPanic("len out of range", func() {_ = make(T, n)})
+ shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ var t *byte
+ if unsafe.Sizeof(t) == 8 {
+ n = 1<<20
+ n <<= 20
+ shouldPanic("len out of range", func() {_ = make(T, n)})
+ shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ n <<= 20
+ shouldPanic("len out of range", func() {_ = make(T, n)})
+ shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ } else {
+ n = 1<<31 - 1
+ shouldPanic("len out of range", func() {_ = make(T, n)})
+ shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ }
+}
+
+func shouldPanic(str string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("did not panic")
+ }
+ s := err.(error).Error()
+ if !strings.Contains(s, str) {
+ panic("got panic " + s + ", want " + str)
+ }
+ }()
+
+ f()
+}