Commit bbf9e6db authored by Alex Brainman's avatar Alex Brainman

internal/poll: cap reads and writes to 1GB on windows

Fixes #26923

Change-Id: I62fec814220ccdf7acd8d79a133d1add3f24cf98
Reviewed-on: https://go-review.googlesource.com/129137Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 4545fea4
...@@ -116,11 +116,17 @@ func (o *operation) InitBufs(buf *[][]byte) { ...@@ -116,11 +116,17 @@ func (o *operation) InitBufs(buf *[][]byte) {
o.bufs = o.bufs[:0] o.bufs = o.bufs[:0]
} }
for _, b := range *buf { for _, b := range *buf {
var p *byte if len(b) == 0 {
o.bufs = append(o.bufs, syscall.WSABuf{})
continue
}
for len(b) > maxRW {
o.bufs = append(o.bufs, syscall.WSABuf{Len: maxRW, Buf: &b[0]})
b = b[maxRW:]
}
if len(b) > 0 { if len(b) > 0 {
p = &b[0] o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]})
} }
o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: p})
} }
} }
...@@ -461,6 +467,11 @@ func (fd *FD) Shutdown(how int) error { ...@@ -461,6 +467,11 @@ func (fd *FD) Shutdown(how int) error {
return syscall.Shutdown(fd.Sysfd, how) return syscall.Shutdown(fd.Sysfd, how)
} }
// Windows ReadFile and WSARecv use DWORD (uint32) parameter to pass buffer length.
// This prevents us reading blocks larger than 4GB.
// See golang.org/issue/26923.
const maxRW = 1 << 30 // 1GB is large enough and keeps subsequent reads aligned
// Read implements io.Reader. // Read implements io.Reader.
func (fd *FD) Read(buf []byte) (int, error) { func (fd *FD) Read(buf []byte) (int, error) {
if err := fd.readLock(); err != nil { if err := fd.readLock(); err != nil {
...@@ -468,6 +479,10 @@ func (fd *FD) Read(buf []byte) (int, error) { ...@@ -468,6 +479,10 @@ func (fd *FD) Read(buf []byte) (int, error) {
} }
defer fd.readUnlock() defer fd.readUnlock()
if len(buf) > maxRW {
buf = buf[:maxRW]
}
var n int var n int
var err error var err error
if fd.isFile || fd.isDir || fd.isConsole { if fd.isFile || fd.isDir || fd.isConsole {
...@@ -581,6 +596,10 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) { ...@@ -581,6 +596,10 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) {
} }
defer fd.decref() defer fd.decref()
if len(b) > maxRW {
b = b[:maxRW]
}
fd.l.Lock() fd.l.Lock()
defer fd.l.Unlock() defer fd.l.Unlock()
curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) curoffset, e := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
...@@ -611,6 +630,9 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) { ...@@ -611,6 +630,9 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
if len(buf) == 0 { if len(buf) == 0 {
return 0, nil, nil return 0, nil, nil
} }
if len(buf) > maxRW {
buf = buf[:maxRW]
}
if err := fd.readLock(); err != nil { if err := fd.readLock(); err != nil {
return 0, nil, err return 0, nil, err
} }
...@@ -639,15 +661,21 @@ func (fd *FD) Write(buf []byte) (int, error) { ...@@ -639,15 +661,21 @@ func (fd *FD) Write(buf []byte) (int, error) {
} }
defer fd.writeUnlock() defer fd.writeUnlock()
ntotal := 0
for len(buf) > 0 {
b := buf
if len(b) > maxRW {
b = b[:maxRW]
}
var n int var n int
var err error var err error
if fd.isFile || fd.isDir || fd.isConsole { if fd.isFile || fd.isDir || fd.isConsole {
fd.l.Lock() fd.l.Lock()
defer fd.l.Unlock() defer fd.l.Unlock()
if fd.isConsole { if fd.isConsole {
n, err = fd.writeConsole(buf) n, err = fd.writeConsole(b)
} else { } else {
n, err = syscall.Write(fd.Sysfd, buf) n, err = syscall.Write(fd.Sysfd, b)
} }
if err != nil { if err != nil {
n = 0 n = 0
...@@ -657,12 +685,18 @@ func (fd *FD) Write(buf []byte) (int, error) { ...@@ -657,12 +685,18 @@ func (fd *FD) Write(buf []byte) (int, error) {
race.ReleaseMerge(unsafe.Pointer(&ioSync)) race.ReleaseMerge(unsafe.Pointer(&ioSync))
} }
o := &fd.wop o := &fd.wop
o.InitBuf(buf) o.InitBuf(b)
n, err = wsrv.ExecIO(o, func(o *operation) error { n, err = wsrv.ExecIO(o, func(o *operation) error {
return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) return syscall.WSASend(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
}) })
} }
return n, err ntotal += n
if err != nil {
return ntotal, err
}
buf = buf[n:]
}
return ntotal, nil
} }
// writeConsole writes len(b) bytes to the console File. // writeConsole writes len(b) bytes to the console File.
...@@ -709,7 +743,7 @@ func (fd *FD) writeConsole(b []byte) (int, error) { ...@@ -709,7 +743,7 @@ func (fd *FD) writeConsole(b []byte) (int, error) {
} }
// Pwrite emulates the Unix pwrite system call. // Pwrite emulates the Unix pwrite system call.
func (fd *FD) Pwrite(b []byte, off int64) (int, error) { func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
// Call incref, not writeLock, because since pwrite specifies the // Call incref, not writeLock, because since pwrite specifies the
// offset it is independent from other writes. // offset it is independent from other writes.
if err := fd.incref(); err != nil { if err := fd.incref(); err != nil {
...@@ -724,16 +758,27 @@ func (fd *FD) Pwrite(b []byte, off int64) (int, error) { ...@@ -724,16 +758,27 @@ func (fd *FD) Pwrite(b []byte, off int64) (int, error) {
return 0, e return 0, e
} }
defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart) defer syscall.Seek(fd.Sysfd, curoffset, io.SeekStart)
ntotal := 0
for len(buf) > 0 {
b := buf
if len(b) > maxRW {
b = b[:maxRW]
}
var n uint32
o := syscall.Overlapped{ o := syscall.Overlapped{
OffsetHigh: uint32(off >> 32), OffsetHigh: uint32(off >> 32),
Offset: uint32(off), Offset: uint32(off),
} }
var done uint32 e = syscall.WriteFile(fd.Sysfd, b, &n, &o)
e = syscall.WriteFile(fd.Sysfd, b, &done, &o) ntotal += int(n)
if e != nil { if e != nil {
return 0, e return ntotal, e
}
buf = buf[n:]
off += int64(n)
} }
return int(done), nil return ntotal, nil
} }
// Writev emulates the Unix writev system call. // Writev emulates the Unix writev system call.
...@@ -765,13 +810,26 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { ...@@ -765,13 +810,26 @@ func (fd *FD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
return 0, err return 0, err
} }
defer fd.writeUnlock() defer fd.writeUnlock()
ntotal := 0
for len(buf) > 0 {
b := buf
if len(b) > maxRW {
b = b[:maxRW]
}
o := &fd.wop o := &fd.wop
o.InitBuf(buf) o.InitBuf(b)
o.sa = sa o.sa = sa
n, err := wsrv.ExecIO(o, func(o *operation) error { n, err := wsrv.ExecIO(o, func(o *operation) error {
return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) return syscall.WSASendto(o.fd.Sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
}) })
return n, err ntotal += int(n)
if err != nil {
return ntotal, err
}
buf = buf[n:]
}
return ntotal, nil
} }
// Call ConnectEx. This doesn't need any locking, since it is only // Call ConnectEx. This doesn't need any locking, since it is only
...@@ -986,6 +1044,10 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er ...@@ -986,6 +1044,10 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er
} }
defer fd.readUnlock() defer fd.readUnlock()
if len(p) > maxRW {
p = p[:maxRW]
}
o := &fd.rop o := &fd.rop
o.InitMsg(p, oob) o.InitMsg(p, oob)
o.rsa = new(syscall.RawSockaddrAny) o.rsa = new(syscall.RawSockaddrAny)
...@@ -1004,6 +1066,10 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er ...@@ -1004,6 +1066,10 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er
// WriteMsg wraps the WSASendMsg network call. // WriteMsg wraps the WSASendMsg network call.
func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) { func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
if len(p) > maxRW {
return 0, 0, errors.New("packet is too large (only 1GB is allowed)")
}
if err := fd.writeLock(); err != nil { if err := fd.writeLock(); err != nil {
return 0, 0, err return 0, 0, err
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment