Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/sys/windows: non-constant GUID constants #32248

Closed
zx2c4 opened this issue May 25, 2019 · 5 comments
Closed

x/sys/windows: non-constant GUID constants #32248

zx2c4 opened this issue May 25, 2019 · 5 comments
Milestone

Comments

@zx2c4
Copy link
Contributor

@zx2c4 zx2c4 commented May 25, 2019

I intend to add the SHGetKnownFolderPath API to x/sys/windows, because it's the right way for looking up things like where an application should store its configuration or where various other standard folders are located. That's kind of boring. The function takes some constant enumeration parameter indicating which folder type to return. Usually in x/sys/windows for this, we import the symbolic names to make that easier. For example, for CreateWellKnownSid, we have something like this:

const (
        WinNullSid                                    = 0
        WinWorldSid                                   = 1
        WinLocalSid                                   = 2
        WinCreatorOwnerSid                            = 3
        WinCreatorGroupSid                            = 4
        ...
)

And then users get to call CreateWellKnownSid(WinCreatorGroupSid) or something.

So far so good.

What's interesting is that the SHGetKnownFolderPath API is one that, rather than taking a numerical constant, takes a GUID constant. In C, this generally amounts to the Windows headers declaring a macro that expands to the curly braces defining the complex object, so you only have them in the resultant binary if you use them. In Go, it seems like it might be another story.

There are a few of these types of constant-GUID-taking APIs in x/sys/windows already, and they declare the "constant" GUID as a global variable. For example:

type GUID struct {
        Data1 uint32
        Data2 uint16
        Data3 uint16
        Data4 [8]byte
}
var WSAID_CONNECTEX = GUID{
        0x25a207b9,
        0xddf3,
        0x4660,
        [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
}
var WSAID_WSASENDMSG = GUID{
        0xa441e712,
        0x754f,
        0x43ca,
        [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d},
}
var WSAID_WSARECVMSG = GUID{
        0xf689d7c8,
        0x6f1f,
        0x436b,
        [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22},
}

Two things immediately leap out at me:

  1. Users of the library can modify the value of these at runtime; they're not read-only.
  2. These aren't actually constants, but runtime global variables that I assume are initialized at startup or if the compiler is smart held in some section of the binary.

This seems somewhat bad. Maybe the compiler optimizes (2) away if it's not used? But maybe it doesn't? Does anybody know? I sort of suspect it doesn't.

Getting back to the API I'd like to add, there are quite a few constant GUIDs that will be added as "constants". Due to (1) and (2) above, and the large quantity of these, it seems like declaring them as a var like that would be a really bad idea.

But I don't know of a language construct in Go that would actually fix this the right way, or whether the existing one is fine and the compiler does something smart with it. Does anybody know?

@bradfitz bradfitz changed the title non-constant GUID constants in x/sys/windows x/sys/windows: non-constant GUID constants May 25, 2019
@gopherbot gopherbot added this to the Unreleased milestone May 25, 2019
@bradfitz
Copy link
Contributor

@bradfitz bradfitz commented May 25, 2019

Users of the library can modify the value of these at runtime; they're not read-only.

Go style is generally to trust users with regard to globals that should be read-only. If they want to shoot themselves in the foot, that's their decision. If it was critical, though, you could make them into functions that returned those values. The current linker would be be better at deadcode eliminating those.

These aren't actually constants, but runtime global variables that I assume are initialized at startup or if the compiler is smart held in some section of the binary.

Yes and no. It handles some cases but there's some open work in that area that missed Go 1.13. There will probably be improvements there for Go 1.14+.

@randall77
Copy link
Contributor

@randall77 randall77 commented May 25, 2019

For (2), they will not make it into the final binary if they are not referenced. (If they are either vars as you wrote, or wrapped in a function as Brad suggested.)
The work Brad mentions are for more complicated types (maps, interfaces) not integer types and arrays/structs of the same.

@bradfitz
Copy link
Contributor

@bradfitz bradfitz commented May 26, 2019

@zx2c4, you can confirm that unreferenced variables of that type aren't included in binaries:

package main

func main() {
        println(WSAID_CONNECTEX.Data1)
}

type GUID struct {
        Data1 uint32
        Data2 uint16
        Data3 uint16
        Data4 [8]byte
}

var WSAID_CONNECTEX = GUID{
        0x25a207b9,
        0xddf3,
        0x4660,
        [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
}
var WSAID_WSASENDMSG = GUID{
        0xa441e712,
        0x754f,
        0x43ca,
        [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d},
}

Then:

bradfitz@go:~$ go build x.go
bradfitz@go:~$ go tool nm x | grep WSAID
  4c20a0 D main.WSAID_CONNECTEX
@zx2c4
Copy link
Contributor Author

@zx2c4 zx2c4 commented May 26, 2019

Super, that makes things easy then. Thanks for the clarification.

@zx2c4 zx2c4 closed this May 26, 2019
@gopherbot
Copy link

@gopherbot gopherbot commented Jun 11, 2019

Change https://golang.org/cl/181637 mentions this issue: windows: allow looking up well-known folder paths

gopherbot pushed a commit to golang/sys that referenced this issue Jun 13, 2019
This adds the recommended API for determining well-known folder paths,
such as where to place application configuration data. The MSDN
documentation mentions an optimization for the "current user" by passing
NULL as the token, so we provide both variants.

Updates golang/go#32248

Change-Id: I4a2d5d833543e6a0ba8f318944dd6493a0ec31d3
Reviewed-on: https://go-review.googlesource.com/c/sys/+/181637
Reviewed-by: Jason Donenfeld <Jason@zx2c4.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Run-TryBot: Jason Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
@golang golang locked and limited conversation to collaborators Jun 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.