-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/sys/unix: ioctl wrapper signatures do not match C on Solaris and AIX #59030
Comments
(CC @golang/solaris @golang/illumos) |
Do you propose to change the signature of the cc @ianlancetaylor for whether this type of API change is acceptable. |
There is no reason for Go function signatures to precisely match C function signatures. It's true that the C function takes a 32-bit integer, but it's fine for the Go function to take a 32- or 64-bit integer depending on the platform. Either way you have to pass a magic constant anyhow. The Go code does the right thing when invoking the system call. Closing because I don't think there is anything to do. Please comment if you disagree. |
From a usability and readability perspective, it seems to me like one would expect to be able to write err := unix.IoctlLifreq(tun.ipfd, unix.SIOCGLIFMTU, &l) I'm fairly certain, at least for that ioctl, that my code is the only consumer. The following feels very clunky (as elaborated here: WireGuard/wireguard-go#39 (comment)) : reqnum := int(unix.SIOCGLIFMTU)
err := unix.IoctlLifreq(tun.ipfd, uint(reqnum), &l) I suppose the alternative is to recommend something like: // some helpful comment explaining why this is necessary
SIOCGLIFMTU := unix.SIOCGLIFMTU & 0xffffffff
// ...
err := unix.IoctlLifreq(tun.ipfd, SIOCGLIFMTU, &l) But that too feels kind of gross. I do agree with the reviewer of my other code that the two lines including the extra assignment to do the ioctl looks gross. If nothing else, it would be nice to clean up the test case with at least a better explanation and ideally a cleaner function call. |
Sorry, to be explicit, by "the test case" I mean
|
Maybe we could change |
Heh. Today I learned that the POSIX Actually, https://www.gnu.org/software/gnulib/manual/html_node/ioctl.html links to three different LSB specifications, two of which use The Solaris and Illumos system calls defined in C match the POSIX signature and header file. So I agree that the signatures in |
It gets defined in |
The script can be changed, if we decide to change the constant. |
Thank you for looking into this.
Any suggestions? @cherrymui suggested we could change the way mkerrors.sh defines the constants. Would doing that be backwards compatible with existing code? (My experiments in the go playground suggest not, but I could be doing it wrong...) |
Neither change would be entirely compatible, unfortunately. I'm not sure whether it's worth a breaking change to fix, but in my opinion if it is worthwhile it would be cleaner to change the signature on Solaris to match the C system call signature than to give the constant a value that isn't exactly equal to the value of the C constant. |
You mean change |
Some of these ioctls are very very very likely only in use by my code. It should be fine to do a breaking change on those (in my opinion.) |
For the Lifreq, it could look something like this? diff --git a/unix/syscall_solaris.go b/unix/syscall_solaris.go
index d3444b6..eb01da4 100644
--- a/unix/syscall_solaris.go
+++ b/unix/syscall_solaris.go
@@ -1120,8 +1120,8 @@ func (l *Lifreq) GetLifruUint() uint {
return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
}
-func IoctlLifreq(fd int, req uint, l *Lifreq) error {
- return ioctlPtr(fd, req, unsafe.Pointer(l))
+func IoctlLifreq(fd int, req int, l *Lifreq) error {
+ return ioctlPtr(fd, uint(req), unsafe.Pointer(l))
}
// Strioctl Helpers
diff --git a/unix/syscall_solaris_test.go b/unix/syscall_solaris_test.go
index 6c2b906..dc46bd5 100644
--- a/unix/syscall_solaris_test.go
+++ b/unix/syscall_solaris_test.go
@@ -367,17 +367,13 @@ func TestLifreqGetMTU(t *testing.T) {
if err != nil {
t.Fatalf("could not open udp socket: %v", err)
}
- // SIOCGLIFMTU is negative which confuses the compiler if used inline:
- // Using "unix.IoctlLifreq(ip_fd, unix.SIOCGLIFMTU, &l)" results in
- // "constant -1065850502 overflows uint"
- reqnum := int(unix.SIOCGLIFMTU)
var l unix.Lifreq
for link, mtu := range tc {
err = l.SetName(link)
if err != nil {
t.Fatalf("Lifreq.SetName(%q) failed: %v", link, err)
}
- if err = unix.IoctlLifreq(ip_fd, uint(reqnum), &l); err != nil {
+ if err = unix.IoctlLifreq(ip_fd, unix.SIOCGLIFMTU, &l); err != nil {
t.Fatalf("unable to SIOCGLIFMTU: %v", err)
}
m := l.GetLifruUint() I can open a CR for changing the ioctls that I added for wireguard-go. I'm a little more nervous about any other ones that were added for other purposes. |
Change https://go.dev/cl/476515 mentions this issue: |
Hrm. It appears that this issue also affects Checking various references for |
I believe it is an SVR4 and STREAMS heritage thing, so I would expect to see it in operating systems from that part of the family tree. |
Updating the CL to include aix and zos. |
(Can be assigned to me unless some kind soul has the bandwidth to work on it before me.)
Copied from WireGuard/wireguard-go#39 (comment)
Is it too late?
Regarding ioctls using negative numbers:
Affected functions:
To anyone labeling this issue, this affects both solaris and illumos.
While I'm likely going to be the one doing the work, I could definitely use some guidance on what approach will make the most sense.
The text was updated successfully, but these errors were encountered: