Skip to content

x/sys/unix: mksyscall_solaris.go doesn't deduplicate so libc functions can only be referenced once #45097

@nshalman

Description

@nshalman

This is to document a design decision within a series of commits I will be submitting for review, but I want to lay out the rationale behind the approach for posterity. See golang/sys#102 / https://golang.org/cl/302310 for additional context.

Summary: In order to link to libc function calls more than once in syscall_{solaris,illumos} we need to prevent duplication in the resulting cgo import directives, linkname directives, and variable declarations.

Details:

unix/sycall_solaris.go already contains the following line:

//sys   ioctl(fd int, req uint, arg uintptr) (err error)

so the ioctl wrapper for the libc ioctl function is currently written to only return an error, however the C function signature is (from the man page) is:

int ioctl(int fildes, int request, /* arg */ ...);

I am working on WireGuard/wireguard-go#39 and have the need to perform some ioctls where the return value is needed.
If I attempt to add the following line to the file:

//sys  ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl

And then rerun the regeneration command for unix/zsyscall_solaris_amd64.go I end up with, among other bits of the diff, these hunks (using -U1 to be concise):

diff --git a/unix/zsyscall_solaris_amd64.go b/unix/zsyscall_solaris_amd64.go
index 7099f55..0d7beab 100644
--- a/unix/zsyscall_solaris_amd64.go
+++ b/unix/zsyscall_solaris_amd64.go
@@ -33,2 +33,3 @@ import (
 //go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
+//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
 //go:cgo_import_dynamic libc_poll poll "libc.so"
@@ -164,2 +165,3 @@ import (
 //go:linkname procioctl libc_ioctl
+//go:linkname procioctl libc_ioctl
 //go:linkname procpoll libc_poll
@@ -296,2 +298,3 @@ var (
        procioctl,
+       procioctl,
        procpoll,

Note the doubling. The compiler certainly does:

$ go build
# golang.org/x/sys/unix
./zsyscall_solaris_amd64.go:299:2: procioctl redeclared in this block
        previous declaration at ./zsyscall_solaris_amd64.go:279:2

If we accept that wanting to create this second wrapper for ioctl is reasonable, then we need mksyscall_solaris.go to keep track and not create duplication. Originally I wrote a version that does a very naive tracking of the previously seen values so that consecutive lines could be processed correctly, but a reviewer suggested that using maps would make it safe to do this anywhere in the file.

Possible alternatives:
Replace

//sys  ioctl(fd int, req uint, arg uintptr) (err error)

with e.g.

//sys  ioctl_ret(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl

func ioctl(fd int, req uint, arg uintptr) error {
       _, err := ioctl_ret(fd, req, arg)
       return err
}

This on its face is nice and simple, but it means that all existing codepaths dependent on ioctl suddenly have an extra function call through ioctl_ret (or whatever we name it, this is verbatim from an older attempt). This seems like not a nice thing to do to existing code.

Another alternative would be to hardcode the generated code for ioctlRet into unix/syscall_illumos.go alongside its consumers. Probably fine, but feels inelegant.

One final note:
None of this solves the problem that moving

//sys  ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl

into unix/syscall_illumos.go will cause a similar redeclaration problem because the code generating unix/zsyscall_illumos.go has no insight into the content of unix/{,z}syscall_solaris.go

Thank you, dear reader, for joining me down here in this sadness.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.OS-Solaris

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions