1- Subject: [PATCH] move lpFromlen to heap for WSARecvFrom syscall
1+ Subject: [PATCH] internal/poll: move rsan to heap on windows
2+
3+ According to https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecvfrom,
4+ the memory pointed to by lpFromlen must remain available during the
5+ overlapped I/O, and therefore cannot be allocated on the stack.
6+
7+ CL 685417 moved the rsan field out of the operation struct and placed
8+ it on stack, which violates the above requirement and causes stack
9+ corruption.
10+
11+ Unfortunately, it is no longer possible to cleanly revert CL 685417.
12+ Instead of attempting to revert it, this CL bundles rsan together
13+ with rsa in the same sync.Pool. The new wsaRsa struct is still in the
14+ same size class, so no additional overhead is introduced by this
15+ change.
16+
17+ Fixes #77975.
18+
19+ Change-Id: I5ffbccb332515116ddc03fb7c40ffc9293cad2ab
220---
321Index: src/internal/poll/fd_windows.go
422IDEA additional info:
@@ -7,49 +25,229 @@ Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
725===================================================================
826diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go
927--- a/src/internal/poll/fd_windows.go (revision 8149d992682ce76c6af804b507878e19fc966f7b)
10- +++ b/src/internal/poll/fd_windows.go (revision 25efab96145f416bbae4024e9c110429770b22d1)
11- @@ -76,6 +76,8 @@
12- // fields used by runtime.netpoll
13- runtimeCtx uintptr
14- mode int32
28+ +++ b/src/internal/poll/fd_windows.go (date 1773058735706)
29+ @@ -149,7 +149,7 @@
30+
31+ // newWSAMsg creates a new WSAMsg with the provided parameters.
32+ // Use [freeWSAMsg] to free it.
33+ - func newWSAMsg(p []byte, oob []byte, flags int, unconnected bool) *windows.WSAMsg {
34+ + func newWSAMsg(p []byte, oob []byte, flags int, rsa *wsaRsa) *windows.WSAMsg {
35+ // The returned object can't be allocated in the stack because it is accessed asynchronously
36+ // by Windows in between several system calls. If the stack frame is moved while that happens,
37+ // then Windows may access invalid memory.
38+ @@ -164,33 +164,45 @@
39+ Buf: unsafe.SliceData(oob),
40+ }
41+ msg.Flags = uint32(flags)
42+ - if unconnected {
43+ - msg.Name = wsaRsaPool.Get().(*syscall.RawSockaddrAny)
44+ - msg.Namelen = int32(unsafe.Sizeof(syscall.RawSockaddrAny{}))
45+ + if rsa != nil {
46+ + msg.Name = &rsa.name
47+ + msg.Namelen = rsa.namelen
48+ }
49+ return msg
50+ }
51+
52+ func freeWSAMsg(msg *windows.WSAMsg) {
53+ // Clear pointers to buffers so they can be released by garbage collector.
54+ + msg.Name = nil
55+ + msg.Namelen = 0
56+ msg.Buffers.Len = 0
57+ msg.Buffers.Buf = nil
58+ msg.Control.Len = 0
59+ msg.Control.Buf = nil
60+ - if msg.Name != nil {
61+ - *msg.Name = syscall.RawSockaddrAny{}
62+ - wsaRsaPool.Put(msg.Name)
63+ - msg.Name = nil
64+ - msg.Namelen = 0
65+ - }
66+ wsaMsgPool.Put(msg)
67+ }
68+
69+ + // wsaRsa bundles a [syscall.RawSockaddrAny] with its length for efficient caching.
70+ + //
71+ + // When used by WSARecvFrom, wsaRsa must be on the heap. See
72+ + // https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecvfrom.
73+ + type wsaRsa struct {
74+ + name syscall.RawSockaddrAny
75+ + namelen int32
76+ + }
1577+
16- + rsan int32
78+ var wsaRsaPool = sync.Pool{
79+ New: func() any {
80+ - return new(syscall.RawSockaddrAny)
81+ + return new(wsaRsa)
82+ },
1783 }
84+ +
85+ + func newWSARsa() *wsaRsa {
86+ + rsa := wsaRsaPool.Get().(*wsaRsa)
87+ + rsa.name = syscall.RawSockaddrAny{}
88+ + rsa.namelen = int32(unsafe.Sizeof(syscall.RawSockaddrAny{}))
89+ + return rsa
90+ + }
91+
92+ var operationPool = sync.Pool{
93+ New: func() any {
94+ @@ -737,19 +749,18 @@
1895
19- func (fd *FD) overlapped(o *operation) *syscall.Overlapped {
20- @@ -740,9 +742,9 @@
21- rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
96+ fd.pin('r', &buf[0])
97+
98+ - rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
99+ + rsa := newWSARsa()
22100 defer wsaRsaPool.Put(rsa)
23101 n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
24102- rsan := int32(unsafe.Sizeof(*rsa))
25- + o.rsan = int32(unsafe.Sizeof(*rsa))
26103 var flags uint32
27104- err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
28- + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &o.rsan , &o.o, nil)
105+ + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, & rsa.name , &rsa.namelen , &o.o, nil)
29106 return qty, err
30107 })
31108 err = fd.eofError(n, err)
32- @@ -771,9 +773,9 @@
33- rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
109+ if err != nil {
110+ return n, nil, err
111+ }
112+ - sa, _ := rsa.Sockaddr()
113+ + sa, _ := rsa.name.Sockaddr()
114+ return n, sa, nil
115+ }
116+
117+ @@ -768,19 +779,18 @@
118+
119+ fd.pin('r', &buf[0])
120+
121+ - rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
122+ + rsa := newWSARsa()
34123 defer wsaRsaPool.Put(rsa)
35124 n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
36125- rsan := int32(unsafe.Sizeof(*rsa))
37- + o.rsan = int32(unsafe.Sizeof(*rsa))
38126 var flags uint32
39127- err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
40- + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &o.rsan , &o.o, nil)
128+ + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, & rsa.name , &rsa.namelen , &o.o, nil)
41129 return qty, err
42130 })
43131 err = fd.eofError(n, err)
44- @@ -802,9 +804,9 @@
45- rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
132+ if err != nil {
133+ return n, err
134+ }
135+ - rawToSockaddrInet4(rsa, sa4)
136+ + rawToSockaddrInet4(&rsa.name, sa4)
137+ return n, err
138+ }
139+
140+ @@ -799,19 +809,18 @@
141+
142+ fd.pin('r', &buf[0])
143+
144+ - rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
145+ + rsa := newWSARsa()
46146 defer wsaRsaPool.Put(rsa)
47147 n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
48148- rsan := int32(unsafe.Sizeof(*rsa))
49- + o.rsan = int32(unsafe.Sizeof(*rsa))
50149 var flags uint32
51150- err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &rsan, &o.o, nil)
52- + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, rsa, &o.rsan , &o.o, nil)
151+ + err = syscall.WSARecvFrom(fd.Sysfd, newWsaBuf(buf), 1, &qty, &flags, & rsa.name , &rsa.namelen , &o.o, nil)
53152 return qty, err
54153 })
55154 err = fd.eofError(n, err)
155+ if err != nil {
156+ return n, err
157+ }
158+ - rawToSockaddrInet6(rsa, sa6)
159+ + rawToSockaddrInet6(&rsa.name, sa6)
160+ return n, err
161+ }
162+
163+ @@ -1371,7 +1380,9 @@
164+ p = p[:maxRW]
165+ }
166+
167+ - msg := newWSAMsg(p, oob, flags, true)
168+ + rsa := newWSARsa()
169+ + defer wsaRsaPool.Put(rsa)
170+ + msg := newWSAMsg(p, oob, flags, rsa)
171+ defer freeWSAMsg(msg)
172+ n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
173+ err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
174+ @@ -1396,7 +1407,9 @@
175+ p = p[:maxRW]
176+ }
177+
178+ - msg := newWSAMsg(p, oob, flags, true)
179+ + rsa := newWSARsa()
180+ + defer wsaRsaPool.Put(rsa)
181+ + msg := newWSAMsg(p, oob, flags, rsa)
182+ defer freeWSAMsg(msg)
183+ n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
184+ err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
185+ @@ -1420,7 +1433,9 @@
186+ p = p[:maxRW]
187+ }
188+
189+ - msg := newWSAMsg(p, oob, flags, true)
190+ + rsa := newWSARsa()
191+ + defer wsaRsaPool.Put(rsa)
192+ + msg := newWSAMsg(p, oob, flags, rsa)
193+ defer freeWSAMsg(msg)
194+ n, err := fd.execIO('r', func(o *operation) (qty uint32, err error) {
195+ err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
196+ @@ -1444,15 +1459,18 @@
197+ }
198+ defer fd.writeUnlock()
199+
200+ - msg := newWSAMsg(p, oob, 0, sa != nil)
201+ - defer freeWSAMsg(msg)
202+ + var rsa *wsaRsa
203+ if sa != nil {
204+ + rsa = newWSARsa()
205+ + defer wsaRsaPool.Put(rsa)
206+ var err error
207+ - msg.Namelen, err = sockaddrToRaw(msg.Name, sa)
208+ + rsa.namelen, err = sockaddrToRaw(&rsa.name, sa)
209+ if err != nil {
210+ return 0, 0, err
211+ }
212+ }
213+ + msg := newWSAMsg(p, oob, 0, rsa)
214+ + defer freeWSAMsg(msg)
215+ n, err := fd.execIO('w', func(o *operation) (qty uint32, err error) {
216+ err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
217+ return qty, err
218+ @@ -1471,11 +1489,14 @@
219+ }
220+ defer fd.writeUnlock()
221+
222+ - msg := newWSAMsg(p, oob, 0, sa != nil)
223+ - defer freeWSAMsg(msg)
224+ + var rsa *wsaRsa
225+ if sa != nil {
226+ - msg.Namelen = sockaddrInet4ToRaw(msg.Name, sa)
227+ + rsa = newWSARsa()
228+ + defer wsaRsaPool.Put(rsa)
229+ + rsa.namelen = sockaddrInet4ToRaw(&rsa.name, sa)
230+ }
231+ + msg := newWSAMsg(p, oob, 0, rsa)
232+ + defer freeWSAMsg(msg)
233+ n, err := fd.execIO('w', func(o *operation) (qty uint32, err error) {
234+ err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
235+ return qty, err
236+ @@ -1494,11 +1515,14 @@
237+ }
238+ defer fd.writeUnlock()
239+
240+ - msg := newWSAMsg(p, oob, 0, sa != nil)
241+ - defer freeWSAMsg(msg)
242+ + var rsa *wsaRsa
243+ if sa != nil {
244+ - msg.Namelen = sockaddrInet6ToRaw(msg.Name, sa)
245+ + rsa = newWSARsa()
246+ + defer wsaRsaPool.Put(rsa)
247+ + rsa.namelen = sockaddrInet6ToRaw(&rsa.name, sa)
248+ }
249+ + msg := newWSAMsg(p, oob, 0, rsa)
250+ + defer freeWSAMsg(msg)
251+ n, err := fd.execIO('w', func(o *operation) (qty uint32, err error) {
252+ err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
253+ return qty, err
0 commit comments