]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: note escape of parts of closured-capture vars
authorDavid Chase <drchase@google.com>
Thu, 14 Apr 2016 15:04:00 +0000 (11:04 -0400)
committerDavid Chase <drchase@google.com>
Tue, 19 Apr 2016 18:02:22 +0000 (18:02 +0000)
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>
src/cmd/compile/internal/gc/esc.go
src/runtime/os1_windows.go
test/escape_closure.go

index ff983e717edc722e3d2a9e4380d862277496f640..06b60821431817e0a3405c48ec2f359a5575b695 100644 (file)
@@ -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
        }
index b4411dacc211ca227b88e873b172c5769a6613fe..8e41ac33b1707a8850d887ba5009063f4b4ac401 100644 (file)
@@ -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
index 4cdb06e4c5eecdd2e241004cd7d0bfcd1e16e9fa..f36073e7d0762385775a73349d90f9b5e4481f1c 100644 (file)
@@ -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()
+}