diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/6g/cgen.c | 11 | ||||
-rw-r--r-- | src/cmd/6g/gg.h | 3 | ||||
-rw-r--r-- | src/cmd/6g/ggen.c | 22 | ||||
-rw-r--r-- | src/cmd/6g/gsubr.c | 109 | ||||
-rw-r--r-- | src/cmd/6g/reg.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/align.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 11 | ||||
-rw-r--r-- | src/pkg/runtime/slice.c | 14 |
8 files changed, 121 insertions, 55 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 5cceefd8f..1986e5606 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -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); } diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 75f6c7918..8d0c38385 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -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*); diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 90811ae4e..a920ae9f0 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -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]); diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 2fd9d9400..20b79c0be 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -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, ®node, 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: diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 1d19b32d8..83c2c9d9f 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -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]; diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index e0c617ac1..ba43fa05b 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -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. diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index e65ce5551..06a05895b 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -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? diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c index 040029e5e..722802c00 100644 --- a/src/pkg/runtime/slice.c +++ b/src/pkg/runtime/slice.c @@ -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; |