From 9fc9246bf383eff51592bf8815914ee26a150a1f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 24 May 2010 16:54:24 -0700 Subject: [PATCH] gc: bug281 - bad overlap in stack copy Fixes #807. R=ken2 CC=golang-dev https://golang.org/cl/1283041 --- src/cmd/5g/cgen.c | 32 +++++++++++++++++++++++ src/cmd/6g/cgen.c | 33 +++++++++++++++++++++++- src/cmd/8g/cgen.c | 33 +++++++++++++++++++++++- test/fixedbugs/bug281.go | 55 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/bug281.go diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index cf701a50a0c..8072c3ceb21 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -1053,11 +1053,32 @@ stkof(Node *n) { Type *t; Iter flist; + int32 off; switch(n->op) { case OINDREG: return n->xoffset; + case ODOT: + t = n->left->type; + if(isptr[t->etype]) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + return off + n->xoffset; + + case OINDEX: + t = n->left->type; + if(!isfixedarray(t)) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + if(isconst(n->right, CTINT)) + return off + t->type->width * mpgetfix(n->right->val.u.xval); + return 1000; + case OCALLMETH: case OCALLINTER: case OCALLFUNC: @@ -1106,6 +1127,17 @@ sgen(Node *n, Node *res, int32 w) osrc = stkof(n); odst = stkof(res); + if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + tempname(&tmp, n->type); + sgen(n, &tmp, w); + sgen(&tmp, res, w); + return; + } + if(osrc % 4 != 0 || odst %4 != 0) fatal("sgen: non word(4) aligned offset src %d or dst %d", osrc, odst); diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 30c1904290e..282f6d7be7b 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -938,11 +938,32 @@ stkof(Node *n) { Type *t; Iter flist; + int32 off; switch(n->op) { case OINDREG: return n->xoffset; + case ODOT: + t = n->left->type; + if(isptr[t->etype]) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + return off + n->xoffset; + + case OINDEX: + t = n->left->type; + if(!isfixedarray(t)) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + if(isconst(n->right, CTINT)) + return off + t->type->width * mpgetfix(n->right->val.u.xval); + return 1000; + case OCALLMETH: case OCALLINTER: case OCALLFUNC: @@ -968,7 +989,7 @@ stkof(Node *n) void sgen(Node *n, Node *ns, int32 w) { - Node nodl, nodr, oldl, oldr, cx, oldcx; + Node nodl, nodr, oldl, oldr, cx, oldcx, tmp; int32 c, q, odst, osrc; if(debug['g']) { @@ -989,6 +1010,16 @@ sgen(Node *n, Node *ns, int32 w) osrc = stkof(n); odst = stkof(ns); + if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + tempname(&tmp, n->type); + sgen(n, &tmp, w); + sgen(&tmp, ns, w); + return; + } if(n->ullman >= ns->ullman) { savex(D_SI, &nodr, &oldr, N, types[tptr]); diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index 9ebbc4b4f75..77f9a9364e2 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -439,7 +439,6 @@ Prog* cgenindex(Node *n, Node *res) { Node tmp, lo, hi, zero; - Prog *p; if(!is64(n->type)) { cgen(n, res); @@ -1043,11 +1042,32 @@ stkof(Node *n) { Type *t; Iter flist; + int32 off; switch(n->op) { case OINDREG: return n->xoffset; + case ODOT: + t = n->left->type; + if(isptr[t->etype]) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + return off + n->xoffset; + + case OINDEX: + t = n->left->type; + if(!isfixedarray(t)) + break; + off = stkof(n->left); + if(off == -1000 || off == 1000) + return off; + if(isconst(n->right, CTINT)) + return off + t->type->width * mpgetfix(n->right->val.u.xval); + return 1000; + case OCALLMETH: case OCALLINTER: case OCALLFUNC: @@ -1093,6 +1113,17 @@ sgen(Node *n, Node *res, int32 w) // offset on the stack osrc = stkof(n); odst = stkof(res); + + if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + tempname(&tsrc, n->type); + sgen(n, &tsrc, w); + sgen(&tsrc, res, w); + return; + } nodreg(&dst, types[tptr], D_DI); nodreg(&src, types[tptr], D_SI); diff --git a/test/fixedbugs/bug281.go b/test/fixedbugs/bug281.go new file mode 100644 index 00000000000..821b0282550 --- /dev/null +++ b/test/fixedbugs/bug281.go @@ -0,0 +1,55 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out + +// Copyright 2010 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. + +// http://code.google.com/p/go/issues/detail?id=807 + +package main + +type Point struct { + X, Y int64 +} + +type Rect struct { + Min, Max Point +} + +func (p Point) Sub(q Point) Point { + return Point{p.X-q.X, p.Y-q.Y} +} + +type Obj struct { + bbox Rect +} + +func (o *Obj) Bbox() Rect { + return o.bbox +} + +func (o *Obj) Points() [2]Point{ + return [2]Point{o.bbox.Min, o.bbox.Max} +} + +var x = 0 + +func main() { + o := &Obj{Rect{Point{800, 0}, Point{}}} + p := Point{800, 300} + q := p.Sub(o.Bbox().Min) + if q.X != 0 || q.Y != 300 { + println("BUG dot: ", q.X, q.Y) + return + } + + q = p.Sub(o.Points()[0]) + if q.X != 0 || q.Y != 300 { + println("BUG index const: ", q.X, q.Y) + } + + q = p.Sub(o.Points()[x]) + if q.X != 0 || q.Y != 300 { + println("BUG index var: ", q.X, q.Y) + } +}