1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:54:40 -07:00

bug162, over and over

R=ken
OCL=35919
CL=35919
This commit is contained in:
Russ Cox 2009-10-20 08:03:43 -07:00
parent d6b64f273f
commit 02fd255a14
20 changed files with 483 additions and 61 deletions

View File

@ -610,6 +610,17 @@ agen(Node *n, Node *res)
case ODOTPTR:
cgen(nl, res);
if(n->xoffset != 0) {
// explicit check for nil if struct is large enough
// that we might derive too big a pointer.
if(nl->type->type->width >= unmappedzero) {
regalloc(&n1, types[tptr], res);
gmove(res, &n1);
n1.op = OINDREG;
n1.type = types[TUINT8];
n1.xoffset = 0;
gins(ATESTB, nodintconst(0), &n1);
regfree(&n1);
}
nodconst(&n1, types[TINT64], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
}

View File

@ -57,6 +57,7 @@ EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwslice;
EXTERN Node* throwreturn;
EXTERN vlong unmappedzero;
/*
* gen.c
@ -92,7 +93,7 @@ void sgen(Node*, Node*, int32);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
void naddr(Node*, Addr*);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
int cgen_inline(Node*, Node*);
void restx(Node*, Node*);

View File

@ -1137,7 +1137,7 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
if(strcmp(n->left->sym->package, "sys") != 0)
if(strcmp(n->left->sym->package, "runtime") != 0)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
goto slicearray;
@ -1215,6 +1215,16 @@ slicearray:
}
gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
// if slice could be too big, dereference to
// catch nil array pointer.
if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
n2 = nodes[0];
n2.xoffset = 0;
n2.op = OINDREG;
n2.type = types[TUINT8];
gins(ATESTB, nodintconst(0), &n2);
}
for(i=0; i<5; i++) {
if(nodes[i].op == OREGISTER)
regfree(&nodes[i]);
@ -1241,6 +1251,16 @@ arraytoslice:
n2.xoffset += Array_array;
gins(optoas(OAS, types[tptr]), &nodes[0], &n2);
// if slice could be too big, dereference to
// catch nil array pointer.
if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) {
n2 = nodes[0];
n2.xoffset = 0;
n2.op = OINDREG;
n2.type = types[TUINT8];
gins(ATESTB, nodintconst(0), &n2);
}
for(i=0; i<2; i++) {
if(nodes[i].op == OREGISTER)
regfree(&nodes[i]);

View File

@ -30,6 +30,10 @@
#include "gg.h"
// TODO(rsc): Can make this bigger if we move
// the text segment up higher in 6l for all GOOS.
vlong unmappedzero = 4096;
void
clearp(Prog *p)
{
@ -832,6 +836,7 @@ gins(int as, Node *f, Node *t)
// Node nod;
// int32 v;
Prog *p;
Addr af, at;
// if(f != N && f->op == OINDEX) {
// regalloc(&nod, &regnode, Z);
@ -861,22 +866,46 @@ gins(int as, Node *f, Node *t)
return nil;
}
memset(&af, 0, sizeof af);
memset(&at, 0, sizeof at);
if(f != N)
naddr(f, &af, 1);
if(t != N)
naddr(t, &at, 1);
p = prog(as);
if(f != N)
naddr(f, &p->from);
p->from = af;
if(t != N)
naddr(t, &p->to);
p->to = at;
if(debug['g'])
print("%P\n", p);
return p;
}
static void
checkoffset(Addr *a, int canemitcode)
{
Prog *p;
if(a->offset < unmappedzero)
return;
if(!canemitcode)
fatal("checkoffset %#llx, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit
// test of 0(reg).
p = gins(ATESTB, nodintconst(0), N);
p->to = *a;
p->to.offset = 0;
}
/*
* generate code to compute n;
* make a refer to result.
*/
void
naddr(Node *n, Addr *a)
naddr(Node *n, Addr *a, int canemitcode)
{
a->scale = 0;
a->index = D_NONE;
@ -920,6 +949,7 @@ naddr(Node *n, Addr *a)
a->type = n->val.u.reg+D_INDIR;
a->sym = n->sym;
a->offset = n->xoffset;
checkoffset(a, canemitcode);
break;
case OPARAM:
@ -1002,7 +1032,7 @@ naddr(Node *n, Addr *a)
break;
case OADDR:
naddr(n->left, a);
naddr(n->left, a, canemitcode);
if(a->type >= D_INDIR) {
a->type -= D_INDIR;
break;
@ -1018,24 +1048,28 @@ naddr(Node *n, Addr *a)
case OLEN:
// len of string or slice
naddr(n->left, a);
naddr(n->left, a, canemitcode);
a->offset += Array_nel;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode);
break;
case OCAP:
// cap of string or slice
naddr(n->left, a);
naddr(n->left, a, canemitcode);
a->offset += Array_cap;
if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
checkoffset(a, canemitcode);
break;
// case OADD:
// if(n->right->op == OLITERAL) {
// v = n->right->vconst;
// naddr(n->left, a);
// naddr(n->left, a, canemitcode);
// } else
// if(n->left->op == OLITERAL) {
// v = n->left->vconst;
// naddr(n->right, a);
// naddr(n->right, a, canemitcode);
// } else
// goto bad;
// a->offset += v;
@ -1618,7 +1652,6 @@ optoas(int op, Type *t)
enum
{
ODynam = 1<<0,
OPtrto = 1<<1,
};
static Node clean[20];
@ -1707,7 +1740,7 @@ lit:
reg1 = &clean[cleani-2];
reg->op = OEMPTY;
reg1->op = OEMPTY;
naddr(n, a);
naddr(n, a, 1);
goto yes;
odot:
@ -1720,7 +1753,7 @@ odot:
n1 = *nn;
n1.type = n->type;
n1.xoffset += oary[0];
naddr(&n1, a);
naddr(&n1, a, 1);
goto yes;
}
@ -1744,7 +1777,7 @@ odot:
a->type = D_NONE;
a->index = D_NONE;
naddr(&n1, a);
naddr(&n1, a, 1);
goto yes;
oindex:
@ -1755,18 +1788,12 @@ oindex:
// set o to type of array
o = 0;
if(isptr[l->type->etype]) {
o += OPtrto;
if(l->type->type->etype != TARRAY)
fatal("not ptr ary");
if(l->type->type->bound < 0)
o += ODynam;
} else {
if(l->type->etype != TARRAY)
fatal("not ary");
if(l->type->bound < 0)
o += ODynam;
}
if(isptr[l->type->etype])
fatal("ptr ary");
if(l->type->etype != TARRAY)
fatal("not ary");
if(l->type->bound < 0)
o += ODynam;
w = n->type->width;
if(isconst(r, CTINT))
@ -1785,10 +1812,7 @@ oindex:
// load the array (reg)
if(l->ullman > r->ullman) {
regalloc(reg, types[tptr], N);
if(o & OPtrto)
cgen(l, reg);
else
agen(l, reg);
agen(l, reg);
}
// load the index (reg1)
@ -1804,10 +1828,7 @@ oindex:
// load the array (reg)
if(l->ullman <= r->ullman) {
regalloc(reg, types[tptr], N);
if(o & OPtrto)
cgen(l, reg);
else
agen(l, reg);
agen(l, reg);
}
// check bounds
@ -1818,9 +1839,16 @@ oindex:
n2.type = types[tptr];
n2.xoffset = Array_nel;
} else {
if(l->type->width >= unmappedzero && l->op == OIND) {
// cannot rely on page protections to
// catch array ptr == 0, so dereference.
n2 = *reg;
n2.op = OINDREG;
n2.type = types[TUINT8];
n2.xoffset = 0;
gins(ATESTB, nodintconst(0), &n2);
}
nodconst(&n2, types[TUINT64], l->type->bound);
if(o & OPtrto)
nodconst(&n2, types[TUINT64], l->type->type->bound);
}
gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
@ -1836,7 +1864,7 @@ oindex:
gmove(&n2, reg);
}
naddr(reg1, a);
naddr(reg1, a, 1);
a->offset = 0;
a->scale = w;
a->index = a->type;
@ -1850,10 +1878,7 @@ oindex_const:
// can multiply by width statically
regalloc(reg, types[tptr], N);
if(o & OPtrto)
cgen(l, reg);
else
agen(l, reg);
agen(l, reg);
v = mpgetfix(r->val.u.xval);
if(o & ODynam) {
@ -1881,10 +1906,6 @@ oindex_const:
if(v < 0) {
yyerror("out of bounds on array");
} else
if(o & OPtrto) {
if(v >= l->type->type->bound)
yyerror("out of bounds on array");
} else
if(v >= l->type->bound) {
yyerror("out of bounds on array");
}
@ -1895,7 +1916,7 @@ oindex_const:
n2.xoffset = v*w;
a->type = D_NONE;
a->index = D_NONE;
naddr(&n2, a);
naddr(&n2, a, 1);
goto yes;
yes:

View File

@ -81,7 +81,7 @@ setoutvar(void)
while(t != T) {
n = nodarg(t, 1);
a = zprog.from;
naddr(n, &a);
naddr(n, &a, 0);
bit = mkvar(R, &a);
for(z=0; z<BITS; z++)
ovar.b[z] |= bit.b[z];

View File

@ -63,7 +63,7 @@ widstruct(Type *t, uint32 o, int flag)
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
dowidth(f->type);
if(f->type->width < 0 || f->type->width > 100000000)
if(f->type->width < 0)
fatal("invalid width %lld", f->type->width);
w = f->type->width;
m = arrayelemwidth(f->type);
@ -239,7 +239,7 @@ dowidth(Type *t)
// width of func type is pointer
w = widthptr;
break;
case TFUNCARGS:
// function is 3 cated structures;
// compute their widths as side-effect.

View File

@ -41,12 +41,12 @@ adderr(int line, char *fmt, va_list arg)
{
Fmt f;
Error *p;
fmtstrinit(&f);
fmtprint(&f, "%L: ", line);
fmtvprint(&f, fmt, arg);
fmtprint(&f, "\n");
if(nerr >= merr) {
if(merr == 0)
merr = 16;
@ -71,7 +71,7 @@ static int
errcmp(const void *va, const void *vb)
{
Error *a, *b;
a = (Error*)va;
b = (Error*)vb;
if(a->lineno != b->lineno)
@ -109,11 +109,11 @@ void
yyerrorl(int line, char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
adderr(line, fmt, arg);
va_end(arg);
hcrash();
nerrors++;
if(nerrors >= 10 && !debug['e'])
@ -2394,7 +2394,6 @@ Node*
safeval(Node *n, NodeList **init)
{
Node *l;
Node *r;
Node *a;
// is this a local variable or a dot of a local variable?

View File

@ -100,6 +100,13 @@ runtime·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)
void
runtime·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Slice ret)
{
if(nel > 0 && old == nil) {
// crash if old == nil.
// could give a better message
// but this is consistent with all the in-line checks
// that the compiler inserts for other uses.
*old = 0;
}
if(hb > nel || lb > hb) {
if(debug) {
@ -146,6 +153,13 @@ runtime·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, S
void
runtime·arraytoslice(byte* old, uint32 nel, Slice ret)
{
if(nel > 0 && old == nil) {
// crash if old == nil.
// could give a better message
// but this is consistent with all the in-line checks
// that the compiler inserts for other uses.
*old = 0;
}
// new dope to old array
ret.len = nel;

View File

@ -92,6 +92,68 @@ throw: interface conversion
panic PC=xxx
== nilptr/
=========== nilptr/arrayindex.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/arrayindex1.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/arraytoslice.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/arraytoslice1.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/arraytoslice2.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/slicearray.go
SIGSEGV: segmentation violation
Faulting address: 0xa
pc: xxx
=========== nilptr/structfield.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/structfield1.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/structfield2.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
=========== nilptr/structfieldaddr.go
SIGSEGV: segmentation violation
Faulting address: 0x0
pc: xxx
== fixedbugs/
=========== fixedbugs/bug016.go
@ -140,9 +202,5 @@ panic PC=xxx
== bugs/
=========== bugs/bug162.go
123
BUG: should fail
=========== bugs/bug193.go
BUG: errchk: bugs/bug193.go:14: missing expected error: 'shift'

View File

@ -21,5 +21,5 @@ func main() {
// Pointer offsets and array indices, if they are
// very large, need to dereference the base pointer
// to trigger a trap.
println(p[uintptr(unsafe.Pointer(&x))]);
println(p[uintptr(unsafe.Pointer(&x))]); // should crash
}

View File

@ -0,0 +1,30 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into p[] with a large
// enough index jumps out of the unmapped section
// at the beginning of memory and into valid memory.
// Pointer offsets and array indices, if they are
// very large, need to dereference the base pointer
// to trigger a trap.
var p *[1<<30]byte = nil;
println(p[256<<20]); // very likely to be inside dummy, but should crash
}

View File

@ -0,0 +1,35 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
func f([]byte) {
panic("unreachable");
}
var dummy [512<<20]byte; // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into p[] with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
//
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
var p *[1<<30]byte = nil;
f(p); // should crash
}

View File

@ -0,0 +1,32 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into p[] with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
//
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
var p *[1<<30]byte = nil;
var x []byte = p; // should crash
_ = x;
}

View File

@ -0,0 +1,33 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
var q *[1<<30]byte;
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into p[] with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
//
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
var x []byte;
var y = &x;
*y = q; // should crash (uses arraytoslice runtime routine)
}

31
test/nilptr/slicearray.go Normal file
View File

@ -0,0 +1,31 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into p[] with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
//
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the slice operation
// to do the check.
var p *[1<<30]byte = nil;
var _ []byte = p[10:len(p)-10]; // should crash
}

View File

@ -0,0 +1,33 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
type T struct {
x [256<<20] byte;
i int;
}
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
var t *T;
println(t.i); // should crash
}

View File

@ -0,0 +1,36 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
type T struct {
x [256<<20] byte;
i int;
}
func f() *T {
return nil;
}
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
println(f().i); // should crash
}

View File

@ -0,0 +1,35 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
type T struct {
x [256<<20] byte;
i int;
}
var y *T;
var x = &y;
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
println((*x).i); // should crash
}

View File

@ -0,0 +1,33 @@
// $G $D/$F.go && $L $F.$A && (! ./$A.out || echo BUG: should fail)
// Copyright 2009 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 "unsafe"
var dummy [512<<20]byte; // give us a big address space
type T struct {
x [256<<20] byte;
i int;
}
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
// otherwise there might not be anything mapped
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
panic("dummy too far out");
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the address calculation to check.
var t *T;
println(&t.i); // should crash
}

View File

@ -43,7 +43,7 @@ ulimit -v 4000000
true >pass.out >times.out
for dir in . ken chan interface fixedbugs bugs
for dir in . ken chan interface nilptr fixedbugs bugs
do
echo
echo '==' $dir'/'