Skip to content

cannon/op-program: Support building on go1.22 #12049

@ajsutton

Description

@ajsutton

if you build op-program using go 1.22 instead of go 1.21, it fails to run in cannon with:

runtime: unexpected error while checking standard file descriptor
fatal error:
cannot open standard fds

This isn't a blocker currently because you need to build the exact same op-program as is used in our deployments and CI is using go 1.21 which works (you can build this locally with make reproducible-prestate). But it does mean we're blocked from upgrading to go 1.22 until we fix it.

The problem function in go is:

func checkfds() {
        if islibrary || isarchive {
                // If the program is actually a library, presumably being consumed by
                // another program, we don't want to mess around with the file
                // descriptors.
                return
        }

        const (
                // F_GETFD, EBADF, O_RDWR are standard across all unixes we support, so
                // we define them here rather than in each of the OS specific files.
                F_GETFD = 0x01
                EBADF   = 0x09
                O_RDWR  = 0x02
        )

        devNull := []byte("/dev/null\x00")
        for i := 0; i < 3; i++ {
                ret, errno := fcntl(int32(i), F_GETFD, 0)
                if ret >= 0 {
                        continue
                }

                if errno != EBADF {
                        print("runtime: unexpected error while checking standard file descriptor ", i, ", errno=", errno, "\n")
                        throw("cannot open standard fds")
                }

                if ret := open(&devNull[0], O_RDWR, 0); ret < 0 {
                        print("runtime: standard file descriptor ", i, " closed, unable to open /dev/null, errno=", errno, "\n")
                        throw("cannot open standard fds")
                } else if ret != int32(i) {
                        print("runtime: opened unexpected file descriptor ", ret, " when attempting to open ", i, "\n")
                        throw("cannot open standard fds")
                }
        }
}

which seems to be checking the standard file descriptors (stdin, stdout and stderr) by calling fcntl(I, F_GETFD, 0) but cannon doesn't currently support F_GETFD, only F_GETFL.

It did work with the patch below, but we'd at minimum need to apply the same change to the solidity version, but we should also check it's actually a sensible implementation. From what I can tell FD_CLOEXEC is the only supported flag that can be returned so 0 seems like a sensible option.

diff --git a/cannon/mipsevm/mips.go b/cannon/mipsevm/mips.go
index 95ab8d75d..d45647d71 100644
--- a/cannon/mipsevm/mips.go
+++ b/cannon/mipsevm/mips.go
@@ -156,7 +156,15 @@ func (m *InstrumentedState) handleSyscall() error {
 		}
 	case sysFcntl:
 		// args: a0 = fd, a1 = cmd
-		if a1 == 3 { // F_GETFL: get file descriptor flags
+		if a1 == 1 { // F_GETFD: get file descriptor flags
+			switch a0 {
+			case fdStdin, fdStdout, fdStderr:
+				v0 = 0
+			default:
+				v0 = 0xFFffFFff
+				v1 = MipsEBADF
+			}
+		} else if a1 == 3 { // F_GETFL: get file status flags
 			switch a0 {
 			case fdStdin, fdPreimageRead, fdHintRead:
 				v0 = 0 // O_RDONLY

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions