diff options
author | David Chase <drchase@google.com> | 2016-04-14 11:04:00 -0400 |
---|---|---|
committer | David Chase <drchase@google.com> | 2016-04-19 18:02:22 +0000 |
commit | 14ebc59f6a4c28c7bf27ce47717ce9ced4441eea (patch) | |
tree | b673f2b1cdd915ecebd0d5f66639888067a97a6f | |
parent | df801575131aa0a16046aafe03de8e3283b7735c (diff) | |
download | go-14ebc59f6a4c28c7bf27ce47717ce9ced4441eea.tar.gz go-14ebc59f6a4c28c7bf27ce47717ce9ced4441eea.zip |
cmd/compile: note escape of parts of closured-capture vars
Missed a case for closure calls (OCALLFUNC && indirect) in
esc.go:esccall.
Cleanup to runtime code for windows to more thoroughly hide
a technical escape. Also made code pickier about failing
to late non-optional kernel32.dll.
Revised for 1.6.2
Fixes #14409.
Change-Id: Ie75486a2c8626c4583224e02e4872c2875f7bca5
Reviewed-on: https://go-review.googlesource.com/22050
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
-rw-r--r-- | src/cmd/compile/internal/gc/esc.go | 5 | ||||
-rw-r--r-- | src/runtime/os1_windows.go | 35 | ||||
-rw-r--r-- | test/escape_closure.go | 26 |
3 files changed, 51 insertions, 15 deletions
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index ff983e717e..06b6082143 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -1376,6 +1376,11 @@ func esccall(e *EscState, n *Node, up *Node) { if haspointers(t.Type) { escassign(e, &e.theSink, src) } + } else { // indirect and OCALLFUNC = could be captured variables, too. (#14409) + ll = e.nodeEscState(n).Escretval + for ; ll != nil; ll = ll.Next { + escassignDereference(e, ll.N, fn) + } } return } diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go index b4411dacc2..8e41ac33b1 100644 --- a/src/runtime/os1_windows.go +++ b/src/runtime/os1_windows.go @@ -108,23 +108,28 @@ func asmstdcall(fn unsafe.Pointer) var asmstdcallAddr unsafe.Pointer +func windowsFindfunc(name []byte, lib uintptr) stdFunction { + f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0]))) + return stdFunction(unsafe.Pointer(f)) +} + func loadOptionalSyscalls() { - var buf [50]byte // large enough for longest string - strtoptr := func(s string) uintptr { - buf[copy(buf[:], s)] = 0 // nil-terminated for OS - return uintptr(noescape(unsafe.Pointer(&buf[0]))) - } - l := stdcall1(_LoadLibraryA, strtoptr("kernel32.dll")) - findfunc := func(name string) stdFunction { - f := stdcall2(_GetProcAddress, l, strtoptr(name)) - return stdFunction(unsafe.Pointer(f)) - } - if l != 0 { - _AddDllDirectory = findfunc("AddDllDirectory") - _AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler") - _GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx") - _LoadLibraryExW = findfunc("LoadLibraryExW") + var ( + kernel32dll = []byte("kernel32.dll\000") + addVectoredContinueHandler = []byte("AddVectoredContinueHandler\000") + getQueuedCompletionStatusEx = []byte("GetQueuedCompletionStatusEx\000") + addDllDirectory = []byte("AddDllDirectory\000") + loadLibraryExW = []byte("LoadLibraryExW\000") + ) + + k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) + if k32 == 0 { + throw("kernel32.dll not found") } + _AddDllDirectory = windowsFindfunc(addDllDirectory, k32) + _AddVectoredContinueHandler = windowsFindfunc(addVectoredContinueHandler, k32) + _GetQueuedCompletionStatusEx = windowsFindfunc(getQueuedCompletionStatusEx, k32) + _LoadLibraryExW = windowsFindfunc(loadLibraryExW, k32) } //go:nosplit diff --git a/test/escape_closure.go b/test/escape_closure.go index 4cdb06e4c5..f36073e7d0 100644 --- a/test/escape_closure.go +++ b/test/escape_closure.go @@ -145,3 +145,29 @@ func ClosureCallArgs15() { // BAD: p should not escape here }(&p) // ERROR "&p escapes to heap" "\(func literal\)\(&p\) escapes to heap" } + +func ClosureLeak1(s string) string { // ERROR "ClosureLeak1 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + return ClosureLeak1a(t) // ERROR "ClosureLeak1 ... argument does not escape" +} + +// See #14409 -- returning part of captured var leaks it. +func ClosureLeak1a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return func() string { // ERROR "ClosureLeak1a func literal does not escape" + return a[0] + }() +} + +func ClosureLeak2(s string) string { // ERROR "ClosureLeak2 s does not escape" + t := s + "YYYY" // ERROR "escapes to heap" + c := ClosureLeak2a(t) // ERROR "ClosureLeak2 ... argument does not escape" + return c +} +func ClosureLeak2a(a ...string) string { // ERROR "leaking param: a to result ~r1 level=1" + return ClosureLeak2b(func() string { // ERROR "ClosureLeak2a func literal does not escape" + return a[0] + }) +} +func ClosureLeak2b(f func() string) string { // ERROR "leaking param: f to result ~r1 level=1" + return f() +} |