From 72f772c4d7a84045aa1c4e95a12677b639088144 Mon Sep 17 00:00:00 2001 From: Eric Lagergren Date: Tue, 13 Dec 2022 10:28:36 -0800 Subject: [PATCH] unix: offs2lohi should shift by bits, not bytes Fixes golang/go#57291 Change-Id: I212ab8a9f47563d9c124a0f20c17df35d7aa8e6d Reviewed-on: https://go-review.googlesource.com/c/sys/+/457315 Auto-Submit: Ian Lance Taylor Reviewed-by: Than McIntosh Reviewed-by: Ian Lance Taylor TryBot-Result: Gopher Robot Run-TryBot: Ian Lance Taylor --- unix/syscall_linux.go | 8 +++----- unix/syscall_linux_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index c5a98440e..73b12b680 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -1986,12 +1986,10 @@ func bytes2iovec(bs [][]byte) []Iovec { return iovecs } -// offs2lohi splits offs into its lower and upper unsigned long. On 64-bit -// systems, hi will always be 0. On 32-bit systems, offs will be split in half. -// preadv/pwritev chose this calling convention so they don't need to add a -// padding-register for alignment on ARM. +// offs2lohi splits offs into its low and high order bits. func offs2lohi(offs int64) (lo, hi uintptr) { - return uintptr(offs), uintptr(uint64(offs) >> SizeofLong) + const longBits = SizeofLong * 8 + return uintptr(offs), uintptr(uint64(offs) >> longBits) } func Readv(fd int, iovs [][]byte) (n int, err error) { diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index 9fc641ab7..170e37ee9 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -1099,3 +1099,36 @@ func TestIoctlFileDedupeRange(t *testing.T) { dedupe.Info[1].Bytes_deduped, 0) } } + +// TestPwritevOffsets tests golang.org/issues/57291 where +// offs2lohi was shifting by the size of long in bytes, not bits. +func TestPwritevOffsets(t *testing.T) { + path := filepath.Join(t.TempDir(), "x.txt") + + f, err := os.Create(path) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { f.Close() }) + + const ( + off = 20 + ) + b := [][]byte{{byte(0)}} + n, err := unix.Pwritev(int(f.Fd()), b, off) + if err != nil { + t.Fatal(err) + } + if n != len(b) { + t.Fatalf("expected to write %d, wrote %d", len(b), n) + } + + info, err := f.Stat() + if err != nil { + t.Fatal(err) + } + want := off + int64(len(b)) + if info.Size() != want { + t.Fatalf("expected size to be %d, got %d", want, info.Size()) + } +}