]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: fix and document uses of RegEnumKeyEx
authorMichael Anthony Knyszek <mknyszek@google.com>
Wed, 3 Nov 2021 18:18:18 +0000 (18:18 +0000)
committerMichael Knyszek <mknyszek@google.com>
Thu, 4 Nov 2021 01:44:54 +0000 (01:44 +0000)
RegEnumKeyEx has an undocumented requirement that subsequent calls need
to be made from the same thread. This change documents that requirement
and fixes uses of it in std.

Fixes #49320.

Change-Id: I6d182227e22dd437996a878b3a978943f01b2d61
Reviewed-on: https://go-review.googlesource.com/c/go/+/361154
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/internal/syscall/windows/registry/key.go
src/syscall/syscall_windows.go
src/syscall/zsyscall_windows.go

index ba5c292c5eca7122ead31db0be92d4283b97275d..ec38cf9288a6f66e0848d1e61ee43c6f3b5a5dbb 100644 (file)
 //
 package registry
 
-import "syscall"
+import (
+       "runtime"
+       "syscall"
+)
 
 const (
        // Registry key security and access rights.
@@ -88,6 +91,12 @@ func OpenKey(k Key, path string, access uint32) (Key, error) {
 
 // ReadSubKeyNames returns the names of subkeys of key k.
 func (k Key) ReadSubKeyNames() ([]string, error) {
+       // RegEnumKeyEx must be called repeatedly and to completion.
+       // During this time, this goroutine cannot migrate away from
+       // its current thread. See #49320.
+       runtime.LockOSThread()
+       defer runtime.UnlockOSThread()
+
        names := make([]string, 0)
        // Registry key size limit is 255 bytes and described there:
        // https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx
index 48fedb33d72322e516e0bfff044faa8ca73654f6..69e163e00f28ad7708d998282eb97d898b821c58 100644 (file)
@@ -279,7 +279,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys  RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
 //sys  RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
 //sys  RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
-//sys  RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
+//sys  regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
 //sys  RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
 //sys  getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
 //sys  GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
@@ -1301,3 +1301,31 @@ func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LI
        }
        return al, nil
 }
+
+// RegEnumKeyEx enumerates the subkeys of an open registry key.
+// Each call retrieves information about one subkey. name is
+// a buffer that should be large enough to hold the name of the
+// subkey plus a null terminating character. nameLen is its
+// length. On return, nameLen will contain the actual length of the
+// subkey.
+//
+// Should name not be large enough to hold the subkey, this function
+// will return ERROR_MORE_DATA, and must be called again with an
+// appropriately sized buffer.
+//
+// reserved must be nil. class and classLen behave like name and nameLen
+// but for the class of the subkey, except that they are optional.
+// lastWriteTime, if not nil, will be populated with the time the subkey
+// was last written.
+//
+// The caller must enumerate all subkeys in order. That is
+// RegEnumKeyEx must be called with index starting at 0, incrementing
+// the index until the function returns ERROR_NO_MORE_ITEMS, or with
+// the index of the last subkey (obtainable from RegQueryInfoKey),
+// decrementing until index 0 is enumerated.
+//
+// Successive calls to this API must happen on the same OS thread,
+// so call runtime.LockOSThread before calling this function.
+func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+       return regEnumKeyEx(key, index, name, nameLen, reserved, class, classLen, lastWriteTime)
+}
index 7bfff16be6ac325fa9a406f98b76aa0542b39948..2d6f34e059d75bec84413d7249548a714f3edaeb 100644 (file)
@@ -305,7 +305,7 @@ func RegCloseKey(key Handle) (regerrno error) {
        return
 }
 
-func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+func regEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
        r0, _, _ := Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
        if r0 != 0 {
                regerrno = Errno(r0)