syscall: fix Getdirentries on 32-bit freebsd 12
On freebsd 12, the system call for getdirentries writes 64 bits to
*basep, even on 32-bit systems. Accomodate that by providing a uint64
to the system call and copy the base to/from that uint64.
The uint64 seems to be a virtual file offset, so failing if the high
bits are not zero should be fine for reasonable-sized directories.
Fixes #32498
Change-Id: Ie22c0d301c6091bd20e813432928b24ab95cc314
Reviewed-on: https://go-review.googlesource.com/c/go/+/181377
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 87a27b1..725fe51 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -267,7 +267,21 @@
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
if supportsABI(_ino64First) {
- return getdirentries_freebsd12(fd, buf, basep)
+ if unsafe.Sizeof(*basep) == 64 {
+ return getdirentries_freebsd12(fd, buf, (*uint64)(unsafe.Pointer(basep)))
+ }
+ // The freebsd12 syscall needs a 64-bit base. On 32-bit machines
+ // we can't just use the basep passed in. See #32498.
+ var base uint64 = uint64(*basep)
+ n, err = getdirentries_freebsd12(fd, buf, &base)
+ *basep = uintptr(base)
+ if base>>32 != 0 {
+ // We can't stuff the base back into a uintptr, so any
+ // future calls would be suspect. Generate an error.
+ // EIO is allowed by getdirentries.
+ err = EIO
+ }
+ return
}
// The old syscall entries are smaller than the new. Use 1/4 of the original
@@ -424,7 +438,7 @@
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
-//sys getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) = _SYS_GETDIRENTRIES_FREEBSD12
+//sys getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) = _SYS_GETDIRENTRIES_FREEBSD12
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 8f4234c..ddc265f 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -570,7 +570,7 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index baa7d68..a0f7952 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -570,7 +570,7 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 16e4bc5..2cd23d3 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -570,7 +570,7 @@
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func getdirentries_freebsd12(fd int, buf []byte, basep *uintptr) (n int, err error) {
+func getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
_p0 = unsafe.Pointer(&buf[0])