aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2016-04-14 11:04:00 -0400
committerDavid Chase <drchase@google.com>2016-04-19 18:02:22 +0000
commit14ebc59f6a4c28c7bf27ce47717ce9ced4441eea (patch)
treeb673f2b1cdd915ecebd0d5f66639888067a97a6f
parentdf801575131aa0a16046aafe03de8e3283b7735c (diff)
downloadgo-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.go5
-rw-r--r--src/runtime/os1_windows.go35
-rw-r--r--test/escape_closure.go26
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()
+}