Commit f02067a9 authored by Russ Cox's avatar Russ Cox

cmd/gc: implement latest rules for checking make sizes

Fixes #4085.

R=ken2
CC=golang-dev
https://golang.org/cl/7277047
parent 46d6f3c6
......@@ -43,10 +43,10 @@ mpcmpfixfix(Mpint *a, Mpint *b)
int
mpcmpfixc(Mpint *b, vlong c)
{
Mpint a;
Mpint c1;
mpmovecfix(&a, c);
return mpcmpfixfix(&a, b);
mpmovecfix(&c1, c);
return mpcmpfixfix(b, &c1);
}
int
......
......@@ -32,6 +32,7 @@ static void checkassignlist(NodeList*);
static void stringtoarraylit(Node**);
static Node* resolve(Node*);
static void checkdefergo(Node*);
static int checkmake(Type*, char*, Node*);
static NodeList* typecheckdefstack;
......@@ -1403,22 +1404,20 @@ reswitch:
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;
......@@ -1434,10 +1433,8 @@ reswitch:
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);
......@@ -1453,10 +1450,8 @@ reswitch:
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);
......@@ -3098,3 +3093,33 @@ ret:
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;
}
......@@ -20,7 +20,12 @@ static void growslice1(SliceType*, Slice, intgo, Slice *);
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)
......
// 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"
}
// 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()
}
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