Skip to content

Commit

Permalink
cmd/gc: treat non-local vars inlined into wrapper as escaping
Browse files Browse the repository at this point in the history
The compiler has a phase ordering problem.  Escape analysis runs
before wrapper generation.  When a generated wrapper calls a method
defined in a different package, if that call is inlined, there will be
no escape information for the variables defined in the inlined call.
Those variables will be placed on the stack, which fails if they
actually do escape.

There are probably various complex ways to fix this.  This is a simple
way to avoid it: when a generated wrapper calls a method defined in a
different package, treat all local variables as escaping.

Fixes golang#9537.

Change-Id: I530f39346de16ad173371c6c3f69cc189351a4e9
Reviewed-on: https://go-review.googlesource.com/3092
Reviewed-by: Russ Cox <[email protected]>
  • Loading branch information
ianlancetaylor committed Jan 22, 2015
1 parent 98d9142 commit ec0ebc2
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/cmd/gc/go.h
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,7 @@ EXTERN int funcdepth;
EXTERN int typecheckok;
EXTERN int compiling_runtime;
EXTERN int compiling_wrappers;
EXTERN int inl_nonlocal;
EXTERN int use_writebarrier;
EXTERN int pure_go;
EXTERN char* flag_installsuffix;
Expand Down
9 changes: 6 additions & 3 deletions src/cmd/gc/inl.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,9 +804,12 @@ inlvar(Node *var)
n->curfn = curfn; // the calling function, not the called one
n->addrtaken = var->addrtaken;

// esc pass wont run if we're inlining into a iface wrapper
// luckily, we can steal the results from the target func
if(var->esc == EscHeap)
// Esc pass wont run if we're inlining into a iface wrapper.
// Luckily, we can steal the results from the target func.
// If inlining a function defined in another package after
// escape analysis is done, treat all local vars as escaping.
// See issue 9537.
if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME))
addrescapes(n);

curfn->dcl = list(curfn->dcl, n);
Expand Down
9 changes: 9 additions & 0 deletions src/cmd/gc/subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2617,7 +2617,16 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
fn->dupok = 1;
typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop);

// Set inl_nonlocal to whether we are calling a method on a
// type defined in a different package. Checked in inlvar.
if(!methodrcvr->local)
inl_nonlocal = 1;

inlcalls(fn);

inl_nonlocal = 0;

curfn = nil;
funccompile(fn, 0);
}
Expand Down
25 changes: 25 additions & 0 deletions test/fixedbugs/issue9537.dir/a.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 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 a

type X struct {
T [32]byte
}

func (x *X) Get() []byte {
t := x.T
return t[:]
}

func (x *X) RetPtr(i int) *int {
i++
return &i
}

func (x *X) RetRPtr(i int) (r1 int, r2 *int) {
r1 = i + 1
r2 = &r1
return
}
43 changes: 43 additions & 0 deletions test/fixedbugs/issue9537.dir/b.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2015 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 (
"bytes"

"./a"
)

type X struct {
*a.X
}

type Intf interface {
Get() []byte
RetPtr(int) *int
RetRPtr(int) (int, *int)
}

func main() {
x := &a.X{T: [32]byte{1, 2, 3, 4}}
var ix Intf = X{x}
t1 := ix.Get()
t2 := x.Get()
if !bytes.Equal(t1, t2) {
panic(t1)
}

p1 := ix.RetPtr(5)
p2 := x.RetPtr(7)
if *p1 != 6 || *p2 != 8 {
panic(*p1)
}

r1, r2 := ix.RetRPtr(10)
r3, r4 := x.RetRPtr(13)
if r1 != 11 || *r2 != 11 || r3 != 14 || *r4 != 14 {
panic("bad RetRPtr")
}
}
10 changes: 10 additions & 0 deletions test/fixedbugs/issue9537.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// rundir

// Copyright 2015 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.

// Issue 9537: Compiler does not run escape analysis on an inlined
// generated method wrapper.

package ignored

0 comments on commit ec0ebc2

Please sign in to comment.