- 
                Notifications
    You must be signed in to change notification settings 
- Fork 3.8k
Description
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