Go version

go1.25rc3 windows/amd64

Output of go env in your module/workspace:

set AR=ar
set CC=gcc
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=1
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=
set GOAMD64=v3
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=E:\Programs\Omion\go
set GOCACHE=C:\Users\Omion\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\Omion\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\Omion\AppData\Local\Temp\go-build3306884133=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=D:\Documents\git\lsmbackup\go.mod
set GOMODCACHE=C:\Users\Omion\go\pkg\mod
set GONOPROXY=myhost.example.org
set GONOSUMDB=myhost.example.org
set GOOS=windows
set GOPATH=C:\Users\Omion\go
set GOPRIVATE=myhost.example.org
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Users\Omion\sdk\go1.25rc3
set GOSUMDB=sum.golang.org
set GOTELEMETRY=local
set GOTELEMETRYDIR=C:\Users\Omion\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Users\Omion\sdk\go1.25rc3\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.25rc3
set GOWORK=
set PKG_CONFIG=pkg-config

What did you do?

Attempted to use the new 1.25 Windows asynchronous IO on a volume handle via: * windows.CreateFile(..., windows.FILE_FLAG_OVERLAPPED) * os.NewFile(...) * file.ReadAt(...)

The problem seems to be that, for whatever reason, Windows disallows seeking on asynchronous volume handles. This is normally not a problem, since changing the file position is useless on an asynchronous handle (they need an OVERLAPPED structure for I/O, and if an OVERLAPPED structure is specified the file position is not used). However, Go calls syscall.Seek twice in the internal/poll/*FD.Pread function, used for ReadAt.

The fix for this would be to not call syscall.Seek in Pread (and probably also Pwrite - it seems like it would have the same problem) for files opened with FILE_FLAG_OVERLAPPED.

I think removing syscall.Seek could be done (though I'm not sure I understand all edge cases):

  • The two syscall.Seek() in Pread (and similarly in Pwrite) could be removed, and the deferred fd.setOffset(curoffset) could be based off of the initial fd.offset instead of the Seek.
  • poll/*FD.Seek would have to be changed for whence==io.SeekCur, but it could be converted to using whence==io.SeekSet and adding fd.offset to the passed offset. Neither of the other whences would have to change, as they do not use the file position as an input.

I suspect it's not a problem that most people will have. However, my use case requires volume handles, and I was hoping to get rid of my home-built IOCP processor. It would make my code quite a bit cleaner.

I have attached an example file that demonstrates this problem (renamed from .go to .txt to make Github happy). HOWEVER, it must be run as administrator and involves opening raw volumes, which is generally a dangerous thing to do. Caution is advised! nativeasync.txt

What did you see happen?

ReadAt fails with "The parameter is incorrect"

What did you expect to see?

No error returned, like with synchronous handles and asynchronous handles to files.

Comment From: gabyhelp

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: dmitshur

Thanks for the report.

CC @golang/windows.