]> Cypherpunks repositories - gostls13.git/commitdiff
bug162, over and over
authorRuss Cox <rsc@golang.org>
Tue, 20 Oct 2009 15:03:43 +0000 (08:03 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 20 Oct 2009 15:03:43 +0000 (08:03 -0700)
R=ken
OCL=35919
CL=35919

20 files changed:
src/cmd/6g/cgen.c
src/cmd/6g/gg.h
src/cmd/6g/ggen.c
src/cmd/6g/gsubr.c
src/cmd/6g/reg.c
src/cmd/gc/align.c
src/cmd/gc/subr.c
src/pkg/runtime/slice.c
test/golden.out
test/nilptr/arrayindex.go [moved from test/bugs/bug162.go with 91% similarity]
test/nilptr/arrayindex1.go [new file with mode: 0644]
test/nilptr/arraytoslice.go [new file with mode: 0644]
test/nilptr/arraytoslice1.go [new file with mode: 0644]
test/nilptr/arraytoslice2.go [new file with mode: 0644]
test/nilptr/slicearray.go [new file with mode: 0644]
test/nilptr/structfield.go [new file with mode: 0644]
test/nilptr/structfield1.go [new file with mode: 0644]
test/nilptr/structfield2.go [new file with mode: 0644]
test/nilptr/structfieldaddr.go [new file with mode: 0644]
test/run

index 5cceefd8f98d0554cbc2e90e3904262b0c0f47df..1986e56065844bf550b31db759bb0988f3aa5fa0 100644 (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);
                }
index 75f6c7918b5648017cfd2329b355655dfb600f9f..8d0c38385653a856edd63710d21739548d53035a 100644 (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*);
index 90811ae4e3348949587816a588c0cab3b6b023e9..a920ae9f08d868de7bab2a911ce27c131d115be1 100644 (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]);
index 2fd9d94009a3d80f6b000808de7b562da1a1e848..20b79c0be99f700489ae20feaeb4fe37c3052ea6 100644 (file)
 
 #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:
index 1d19b32d80da9890084d1e7734d80f753c776032..83c2c9d9f40476a514bd49fb7b11ebab40e116c7 100644 (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];
index e0c617ac10b2c35a74746df6d50d0685adb6e49a..ba43fa05ba47db59612a73890ba8c0d718fe0d5e 100644 (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.
index e65ce5551946aee69b078c61bdb6a48e0ddf7ca3..06a05895b116263df9061540c77b2a896a559be7 100644 (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?
index 040029e5ea71f010074b686da447a408357718fc..722802c004cd8a459a8b753ec5e44c89a753e1cf 100644 (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;
index 2f21c1d205bca196484ae9317acbe04781e04d6d..79c2990bb1baf8b39c1ed8c4e23b1c3d6e1810ec 100644 (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'
similarity index 91%
rename from test/bugs/bug162.go
rename to test/nilptr/arrayindex.go
index 717f1f0a4d5b84075a2b28b1a765c93f3ea6e021..0bc6bf4a890d88d589ddabf8119e7b6c9b3700c7 100644 (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
 }
diff --git a/test/nilptr/arrayindex1.go b/test/nilptr/arrayindex1.go
new file mode 100644 (file)
index 0000000..ac72b78
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/arraytoslice.go b/test/nilptr/arraytoslice.go
new file mode 100644 (file)
index 0000000..07ecfe0
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/arraytoslice1.go b/test/nilptr/arraytoslice1.go
new file mode 100644 (file)
index 0000000..78c0d85
--- /dev/null
@@ -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;
+}
diff --git a/test/nilptr/arraytoslice2.go b/test/nilptr/arraytoslice2.go
new file mode 100644 (file)
index 0000000..52a238e
--- /dev/null
@@ -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)
+}
diff --git a/test/nilptr/slicearray.go b/test/nilptr/slicearray.go
new file mode 100644 (file)
index 0000000..d1d2a25
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/structfield.go b/test/nilptr/structfield.go
new file mode 100644 (file)
index 0000000..51da7a9
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/structfield1.go b/test/nilptr/structfield1.go
new file mode 100644 (file)
index 0000000..5390a64
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/structfield2.go b/test/nilptr/structfield2.go
new file mode 100644 (file)
index 0000000..f11e3df
--- /dev/null
@@ -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
+}
diff --git a/test/nilptr/structfieldaddr.go b/test/nilptr/structfieldaddr.go
new file mode 100644 (file)
index 0000000..5ac5dee
--- /dev/null
@@ -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
+}
index 8b3bc4149c7390405849eff3cf1336a8722a7f25..aa4b6003d2b4f0c93f08922bb649d4b3924d9f8d 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -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'/'