Skip to content

x/sys/unix, syscall: incorrect return value as output parameter on s390x Big Endian #70302

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

Closed
xbt573 opened this issue Nov 12, 2024 · 3 comments
Labels
arch-s390x Issues solely affecting the s390x architecture. compiler/runtime Issues related to the Go compiler and/or runtime.
Milestone

Comments

@xbt573
Copy link

xbt573 commented Nov 12, 2024

Go version

go version go1.23.2 linux/s390x

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='s390x'
GOBIN=''
GOCACHE='/home/xbt573/.cache/go-build'
GOENV='/home/xbt573/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='s390x'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/xbt573/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/xbt573/go'
GOPRIVATE=''
GOPROXY='direct'
GOROOT='/usr/lib/golang'
GOSUMDB='off'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/golang/pkg/tool/linux_s390x'
GOVCS=''
GOVERSION='go1.23.2'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/xbt573/.config/go/telemetry'
GCCGO='gccgo'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -march=z196 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1678900633=/tmp/go-build -gno-record-gcc-switches'

What did you do?

package main

import (
        "os"
        "fmt"
        "syscall"
        "unsafe"
        "golang.org/x/sys/unix"
)

func main() {
        f, err := os.Open(os.Args[1])
        if err != nil {
                panic(err)
        }
        defer f.Close()

        var attr int

        _, _, rerr := unix.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(unix.FS_IOC_GETFLAGS), uintptr(unsafe.Pointer(&attr)))
        if rerr != 0 {
                panic(rerr)
        }

        fmt.Println(attr)
}
$ ./playground /path/to/file/

C equivalent if you want to test it on the same machine:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#include <linux/fs.h>

int main(int argc, char **argv) {
        int fd, r, f;

        fd = open(argv[1], O_RDONLY|O_NONBLOCK|O_NOFOLLOW);
        if (fd == -1) {
                return 1;
        }
        r = ioctl(fd, FS_IOC_GETFLAGS, &f);
        if (r == -1) {
                return 2;
        }

        printf("%d\n", f);

        close(fd);

}

What did you see happen?

This program returns 549755813888 for file, which flags supposed to be 128, almost identical C program also returns 128 as it is expected. Note that 128 << 32 == 549755813888. I think this bug is caused by big-endianness of s390x architecture.

What did you expect to see?

I expected to see correct return value from output parameter (number 128).

Example file with the same flags (128) can be created with following commands

$ touch example
# chattr +A example
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Nov 12, 2024
@xbt573
Copy link
Author

xbt573 commented Nov 12, 2024

I suppose use of IoctlGetUint32 is not always safe because FS_IOC_GETFLAGS is limited to C long, which can (but can not) be bigger than uint32.

https://github.com/torvalds/linux/blob/master/include/uapi/linux/fs.h#L223

@seankhliao seankhliao changed the title golang.org/x/sys/unix, syscall: Incorrect return value as output parameter on Big Endian x/sys/unix, syscall: incorrect return value as output parameter on s390x Big Endian Nov 12, 2024
@seankhliao seankhliao added the arch-s390x Issues solely affecting the s390x architecture. label Nov 12, 2024
@gopherbot gopherbot added this to the Unreleased milestone Nov 12, 2024
@ianlancetaylor
Copy link
Member

The C type int is normally 32 bits. On s390x the Go type int is 64 bits. You can't pass a pointer to a Go int to a system call that is expecting a pointer to a C int. Normally when calling a syscall that expects a pointer to the C type int, you should pass a pointer to the Go type int32.

Closing because there is nothing to change in the Go project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-s390x Issues solely affecting the s390x architecture. compiler/runtime Issues related to the Go compiler and/or runtime.
Projects
None yet
Development

No branches or pull requests

5 participants