-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
cmd/compile: in specific conditions in go1.22rc1, Windows SetFileInformationByHandle returns "Invalid access to memory location" #65069
Comments
CC @golang/compiler, @golang/windows. |
I grabbed the built binaries from a couple GitHub Actions repro/no-repro runs, but For now, I ran |
Thanks for the pointer @alexbrainman. The issue #64729 has the same failure mode as this one, and an easier reproducer. I'm pretty sure that the root cause in both cases is the same as in CL 549256): one of the parameter's memory is not correctly aligned. In fact, For this particular issue, the problem is in the winio.FileBasicInfo definition: type FileBasicInfo struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
FileAttributes uint32
_ uint32 // padding
} The Go compiler uses an alignment of 4 bytes, as windows.Filetime is a struct containing two This is not the first time that The solution here, if I'm not wrong, is to apply the same fix as in https://go-review.googlesource.com/c/go/+/549256 (attn @bcmills). To avoid making a breaking change in go-winio, I would suggest doing something like this: // SetFileBasicInfo sets times and attributes for a file.
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
var tmp = struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
FileAttributes uint32
_ uint32 // padding
}{bi.CreationTime, bi.LastAccessTime, bi.LastWriteTime, bi.ChangeTime, bi.FileAttributes} // This doesn't compile, but you get the idea.
if err := windows.SetFileInformationByHandle(
windows.Handle(f.Fd()),
windows.FileBasicInfo,
(*byte)(unsafe.Pointer(&tmp)),
uint32(unsafe.Sizeof(tmp)),
); err != nil {
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
}
runtime.KeepAlive(f)
return nil
} @dagood, could you fork |
Nice, that works! Thanks. Specifically, tried this: merge := func(t windows.Filetime) uint64 {
return *(*uint64)(unsafe.Pointer(&t))
}
biAligned := struct {
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
FileAttributes uint32
_ uint32 // padding
}{
merge(bi.CreationTime), merge(bi.LastAccessTime), merge(bi.LastWriteTime), merge(bi.ChangeTime),
bi.FileAttributes,
0,
}
if err := windows.SetFileInformationByHandle(
windows.Handle(f.Fd()),
windows.FileBasicInfo,
(*byte)(unsafe.Pointer(&biAligned)),
uint32(unsafe.Sizeof(biAligned)), I suppose we can't say 100% conclusively that this is the cause just because CI passes (adding a fmt call causes it to pass, too) but the logic certainly makes sense. 🙂 I didn't notice the alignment effect of So, I suppose this was caused by the location of Perhaps go-winio can also add tests that check the alignment of the structs as Go sees them vs. the actual C headers (or at least vs. hand-written values derived from the docs). Closing: not a Go bug. |
Reading the nice 1.22 release notes, it looks like it's probably related to this:
The numbers aren't quite the same, but it's the same pattern: this was code that relied on Go using 8 byte (or higher) alignment even though the struct itself only specifies 4 byte alignment. Mentioning in this thread in case anyone finds this issue later without context, or if anyone already here was interested. |
Go version
go1.22rc1
Output of
go env
in your module/workspace:What did you do?
I'm filing this on behalf of moby/moby. This came up in a PR attempting to update from go1.21.5 to go1.22rc1: moby/moby#46982. Unfortunately I haven't been able to get it to repro locally by setting up a simpler repro app, and the moby/moby tests are complex enough that I haven't successfully attempted to run them locally. I forked the project and ran experimental changes in GitHub Actions to try things out, for now.
I wrote more details as I went in microsoft/go#1100, but I'll try to summarize it all here. My GitHub Actions runs are at dagood/moby#1.
What did you see happen?
In GitHub CI, this error shows up reliably for a given commit, on each of the 14 jobs that test it per workflow run:
I was able to add some code to print a stack trace upon error, and got this:
Because the the error itself mentions SetFileInformationByHandle, it seems like this must be related to 549256: internal/syscall/windows: fix the signature of SetFileInformationByHandle (it involves the same function name and the CL and error are both new in go1.22rc1). However, based on the stack trace, I'm not sure it's linked at all. The CL changes
internal/syscall/windows
like this:But fileinfo.go#L38-L55 uses
x/sys/windows
's implementation, which isn't like either of those, accepting*byte
:My next experiment was to try putting
%#v
ofbi
in the error message to see if something's special about the values. That could perhaps help me repro this locally with a simpler program. However... adding afmt.*f
causes the error to stop happening!So, I thought that somehow
bi
wasn't being kept alive, and that's why trying to format it made it work. I removed the formatting code and addedruntime.KeepAlive(bi)
afterruntime.KeepAlive(f)
instead. But the error shows up in this case.This makes me think the compiler is making some decision differently in go1.22rc1 than it did in go1.21.5, leading to this error when combined with this code.
Maybe it's an issue with the library, but I'm not sure how to properly investigate that, and understanding what changed in go1.22rc1 to make this start showing up will help narrow that down at the very least.
What did you expect to see?
No error.
The text was updated successfully, but these errors were encountered: