Skip to content

syscall: should not clear nofile rlimit cache when setting other process's nofile rlimit #67184

Closed
@lifubang

Description

@lifubang

Go version

go version go1.19

Output of go env in your module/workspace:

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/acmcoder/.cache/go-build"
GOENV="/home/acmcoder/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/acmcoder/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/acmcoder/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.19.13"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build6687487=/tmp/go-build -gno-record-gcc-switches"

What did you do?

When we use unix.Prlimit to set other process's nofile limit, we should not clear the calling process's nofile limit cache, it will cause the nofile limit setting invalid when we use unix.Exec.
The reprodecing code:

package main

import (
	"fmt"
	"os"
	"os/exec"

	"golang.org/x/sys/unix"
)

func main() {
	// Usage: ./prlimit true or ./prlimit false
	ifPrlimit := os.Args[1]
	if ifPrlimit == "true" {
		fmt.Println("Prlimit is true")
	} else {
		fmt.Println("Prlimit is false")
	}

	// Start a child process firstly,
	// so we can use Prlimit to set it's nofile rlimit.
	cmd := exec.Command("sleep", "infinity")
	cmd.Start()

	// To print out the process's nofile limit
	var lim unix.Rlimit
	if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &lim); err == nil {
		fmt.Printf("(1) init curr: %d, max: %d\n", lim.Cur, lim.Max)
	}

	// If we run ./prlimit true, we use unix.Prlimit to set child process's nofile limit,
	// then it will cause a bug for calling process.
	if ifPrlimit == "true" {
		if err := unix.Prlimit(cmd.Process.Pid, unix.RLIMIT_NOFILE, &lim, nil); err != nil {
			fmt.Println("Prlimit failed", err)
		}
		cmd.Process.Kill()
		cmd.Process.Wait()
		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &lim); err == nil {
			fmt.Printf("(2) after Prlimit other process, curr: %d, max: %d\n", lim.Cur, lim.Max)
		}
	}

	// The above mentiond bug is here.
	unix.Exec("/bin/sh", []string{"/bin/sh", "-c", "ulimit -n"}, os.Environ())
}

What did you see happen?

acmcoder@acmcoder:~/rlimits$ # Execve a process without Prlimit
acmcoder@acmcoder:~/rlimits$ ./prlimit false
Prlimit is false
(1) init curr: 1048576, max: 1048576
1024

acmcoder@acmcoder:~/rlimits$ # Execve a process after Prlimit
acmcoder@acmcoder:~/rlimits$ ./prlimit true
Prlimit is true
(1) init curr: 1048576, max: 1048576
(2) after Prlimit other process, curr: 1048576, max: 1048576
1048576

What did you expect to see?

The last output of ./prlimit true should be the same as ./prlimit false.

Metadata

Metadata

Labels

FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions