diff options
author | Kai Backman <kaib@golang.org> | 2009-10-26 21:49:32 -0700 |
---|---|---|
committer | Kai Backman <kaib@golang.org> | 2009-10-26 21:49:32 -0700 |
commit | a0857e4a2dc0f11b2a6a0f859f885ac7091e6c09 (patch) | |
tree | b315bf7d87ae5cdb423b2b81094a261ad9f090f5 /src | |
parent | 66e6b26cdfe2db2a956b3a6fc7da97ee14bb0cd3 (diff) | |
download | golang-a0857e4a2dc0f11b2a6a0f859f885ac7091e6c09.tar.gz |
bug162, large indices on nil references
R=rsc
http://go/go-review/1013016
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/5g/cgen.c | 10 | ||||
-rw-r--r-- | src/cmd/5g/gg.h | 3 | ||||
-rw-r--r-- | src/cmd/5g/gsubr.c | 72 |
3 files changed, 71 insertions, 14 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index f36ba09a0..e213ddf17 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -702,6 +702,16 @@ 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], N); + gmove(res, &n1); + p1 = gins(AMOVW, &n1, &n1); + p1->from.type = D_OREG; + p1->from.offset = 0; + regfree(&n1); + } nodconst(&n1, types[TINT32], n->xoffset); regalloc(&n2, n1.type, N); regalloc(&n3, types[tptr], N); diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 56bb0c557..04b16d2c1 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -62,6 +62,7 @@ EXTERN Node* deferproc; EXTERN Node* deferreturn; EXTERN Node* throwindex; EXTERN Node* throwreturn; +EXTERN long unmappedzero; EXTERN int maxstksize; /* @@ -99,7 +100,7 @@ void raddr(Node *n, Prog *p); Prog* gcmp(int, Node*, Node*); Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs); Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs); -void naddr(Node*, Addr*); +void naddr(Node*, Addr*, int); void cgen_aret(Node*, Node*); /* diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index a34320f6f..bd5f0de0d 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -30,6 +30,10 @@ #include "gg.h" +// TODO(kaib): Can make this bigger if we move +// the text segment up higher in 5l for all GOOS. +long unmappedzero = 4096; + void clearp(Prog *p) { @@ -863,6 +867,7 @@ gins(int as, Node *f, Node *t) // Node nod; // int32 v; Prog *p; + Addr af, at; if(f != N && f->op == OINDEX) { fatal("gins OINDEX not implemented"); @@ -883,11 +888,16 @@ gins(int as, Node *f, Node *t) // regfree(&nod); } - p = prog(as); + memset(&af, 0, sizeof af); + memset(&at, 0, sizeof at); if(f != N) - naddr(f, &p->from); + naddr(f, &af, 1); if(t != N) - naddr(t, &p->to); + naddr(t, &at, 1); p = prog(as); + if(f != N) + p->from = af; + if(t != N) + p->to = at; if(debug['g']) print("%P\n", p); return p; @@ -901,7 +911,7 @@ raddr(Node *n, Prog *p) { Addr a; - naddr(n, &a); + naddr(n, &a, 1); if(a.type != D_REG && a.type != D_FREG) { if(n) fatal("bad in raddr: %O", n->op); @@ -958,13 +968,33 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) return p; } +static void +checkoffset(Addr *a, int canemitcode) +{ + Prog *p; + Node n1; + + 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). + regalloc(&n1, types[TUINTPTR], N); + p = gins(AMOVW, N, &n1); + p->from = *a; + p->from.offset = 0; + regfree(&n1); +} /* * generate code to compute n; * make a refer to result. */ void -naddr(Node *n, Addr *a) +naddr(Node *n, Addr *a, int canemitcode) { a->type = D_NONE; a->name = D_NONE; @@ -1014,6 +1044,7 @@ naddr(Node *n, Addr *a) a->reg = n->val.u.reg; a->sym = n->sym; a->offset = n->xoffset; + checkoffset(a, canemitcode); break; case OPARAM: @@ -1099,18 +1130,22 @@ 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 OADDR: - naddr(n->left, a); + naddr(n->left, a, canemitcode); switch(a->type) { case D_OREG: a->type = D_CONST; @@ -1558,7 +1593,7 @@ lit: reg1 = &clean[cleani-2]; reg->op = OEMPTY; reg1->op = OEMPTY; - naddr(n, a); + naddr(n, a, 1); goto yes; odot: @@ -1571,7 +1606,7 @@ odot: n1 = *nn; n1.type = n->type; n1.xoffset += oary[0]; - naddr(&n1, a); + naddr(&n1, a, 1); goto yes; } @@ -1595,7 +1630,7 @@ odot: a->type = D_NONE; a->name = D_NONE; - naddr(&n1, a); + naddr(&n1, a, 1); goto yes; oindex: @@ -1669,6 +1704,17 @@ 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[TUINTPTR]; + n2.xoffset = 0; + regalloc(&n3, n2.type, N); + gins(AMOVW, &n2, &n3); + regfree(&n3); + } nodconst(&n2, types[TUINT32], l->type->bound); if(o & OPtrto) nodconst(&n2, types[TUINT32], l->type->type->bound); @@ -1699,7 +1745,7 @@ oindex: else if(*w == 8) gshift(AADD, reg1, SHIFT_LL, 3, reg); - naddr(reg1, a); + naddr(reg1, a, 1); a->type = D_OREG; a->reg = reg->val.u.reg; a->offset = 0; @@ -1763,7 +1809,7 @@ oindex_const: n2.xoffset = v * (*w); a->type = D_NONE; a->name = D_NONE; - naddr(&n2, a); + naddr(&n2, a, 1); goto yes; yes: |