Skip to content

typecheck: false positive "unused variable" and "unused import" in fairly standard code #2014

Closed
@cyphar

Description

@cyphar
  • Yes, I'm using a binary release within 2 latest major releases. Only such installations are supported.
  • Yes, I've searched similar issues on GitHub and didn't find any.
  • Yes, I've included all information below (version, config, etc).
  • Yes, I've tried with the standalone linter if available. (https://golangci-lint.run/usage/linters/)
Description of the problem

Currently there are a couple of false-positive typecheck errors when running golang-ci on the runc codebase. I haven't tried to reduce these to a minimum test case, so these are snippets from the source tree.

The following code from runc trips up typecheck.

// newProcess returns a new libcontainer Process with the arguments from the
// spec and stdio from the current process.
func newProcess(p specs.Process, init bool, logLevel string) (*libcontainer.Process, error) {
	lp := &libcontainer.Process{
		Args: p.Args,
		Env:  p.Env,
		// TODO: fix libcontainer's API to better support uid/gid in a typesafe way.
		User:            fmt.Sprintf("%d:%d", p.User.UID, p.User.GID),
		Cwd:             p.Cwd,
		Label:           p.SelinuxLabel,
		NoNewPrivileges: &p.NoNewPrivileges,
		AppArmorProfile: p.ApparmorProfile,
		Init:            init,
		LogLevel:        logLevel,
	}

	if p.ConsoleSize != nil {
		lp.ConsoleWidth = uint16(p.ConsoleSize.Width)
		lp.ConsoleHeight = uint16(p.ConsoleSize.Height)
	}

	if p.Capabilities != nil {
		lp.Capabilities = &configs.Capabilities{}
		lp.Capabilities.Bounding = p.Capabilities.Bounding
		lp.Capabilities.Effective = p.Capabilities.Effective
		lp.Capabilities.Inheritable = p.Capabilities.Inheritable
		lp.Capabilities.Permitted = p.Capabilities.Permitted
		lp.Capabilities.Ambient = p.Capabilities.Ambient
	}
	for _, gid := range p.User.AdditionalGids {
		lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10))
	}
	for _, rlimit := range p.Rlimits {
		rl, err := createLibContainerRlimit(rlimit)
		if err != nil {
			return nil, err
		}
		lp.Rlimits = append(lp.Rlimits, rl)
	}
	return lp, nil
}
utils_linux.go:129:9: gid declared but not used (typecheck)
        for _, gid := range p.User.AdditionalGids {
               ^
utils_linux.go:133:3: rl declared but not used (typecheck)
                rl, err := createLibContainerRlimit(rlimit)
                ^

And something similar happens with a syscall import:

import (
	"syscall"
)

// ... snip ...

// runContainer runs the container with the specific config and arguments
//
// buffers are returned containing the STDOUT and STDERR output for the run
// along with the exit code and any go error
func runContainer(t *testing.T, config *configs.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) {
	container, err := newContainer(t, config)
	if err != nil {
		return nil, -1, err
	}
	defer destroyContainer(container)
	buffers = newStdBuffers()
	process := &libcontainer.Process{
		Cwd:    "/",
		Args:   args,
		Env:    standardEnvironment,
		Stdin:  buffers.Stdin,
		Stdout: buffers.Stdout,
		Stderr: buffers.Stderr,
		Init:   true,
	}

	err = container.Run(process)
	if err != nil {
		return buffers, -1, err
	}
	ps, err := process.Wait()
	if err != nil {
		return buffers, -1, err
	}
	status := ps.Sys().(syscall.WaitStatus)
	if status.Exited() {
		exitCode = status.ExitStatus()
	} else if status.Signaled() {
		exitCode = -int(status.Signal())
	} else {
		return buffers, -1, err
	}
	return
}
libcontainer/integration/utils_test.go:14:2: "syscall" imported but not used (typecheck)
        "syscall"
        ^
Version of golangci-lint
$ golangci-lint --version
golangci-lint has version 1.40.1 built from 625445b1 on 2021-05-14T11:44:45Z
Config file
$ cat .golangci.yml
run:
  build-tags:
    - seccomp

linters:
  enable:
    - gofmt
Go environment
$ go version && go env
go version go1.16.4 linux/amd64
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/cyphar/.cache/go-build"
GOENV="/home/cyphar/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/cyphar/.local/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/cyphar/.local"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib64/go/1.16"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib64/go/1.16/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.4"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/cyphar/.local/src/github.com/opencontainers/runc/go.mod"
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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build4179905305=/tmp/go-build -gno-record-gcc-switches"
Verbose output of running
$ golangci-lint cache clean
$ golangci-lint run -v
INFO [config_reader] Config search paths: [./ /home/cyphar/.local/src/github.com/opencontainers/runc /home/cyphar/.local/src/github.com/opencontainers /home/cyphar/.local/src/github.com /home/cyphar/.local/src /home/cyphar/.local /home/cyphar /home /]
INFO [config_reader] Used config file .golangci.yml
INFO [lintersdb] Active 11 linters: [deadcode errcheck gofmt gosimple govet ineffassign staticcheck structcheck typecheck unused varcheck]
INFO [loader] Using build tags: [seccomp]
INFO [loader] Go packages loading at mode 575 (exports_file|imports|name|types_sizes|compiled_files|files|deps) took 954.28777ms
INFO [runner/filename_unadjuster] Pre-built 0 adjustments in 33.217745ms
INFO [linters context/goanalysis] analyzers took 18.186819328s with top 10 stages: buildir: 11.987374878s, inspect: 642.888036ms, nilness: 522.874145ms, fact_purity: 422.115043ms, ctrlflow: 385.837038ms, printf: 344.867245ms, fact_deprecated: 314.402418ms, gofmt: 307.800085ms, typedness: 171.428095ms, directives: 170.726644ms
INFO [runner] Issues before processing: 756, after processing: 3
INFO [runner] Processors filtering stat (out/in): filename_unadjuster: 738/738, skip_files: 738/738, skip_dirs: 738/738, identifier_marker: 738/738, diff: 3/3, path_shortener: 3/3, path_prettifier: 738/738, exclude: 738/738, max_same_issues: 3/3, max_from_linter: 3/3, path_prefixer: 3/3, cgo: 738/756, autogenerated_exclude: 738/738, exclude-rules: 668/738, nolint: 399/668, uniq_by_line: 3/399, max_per_file_from_linter: 3/3, source_code: 3/3, severity-rules: 3/3, sort_results: 3/3
INFO [runner] processing took 46.600434ms with stages: exclude-rules: 22.597687ms, identifier_marker: 15.041987ms, nolint: 5.644105ms, path_prettifier: 1.69729ms, autogenerated_exclude: 898.324µs, skip_dirs: 430.279µs, source_code: 84.378µs, cgo: 78.11µs, filename_unadjuster: 60.411µs, uniq_by_line: 53.35µs, max_same_issues: 5.65µs, path_shortener: 2.539µs, max_from_linter: 2.106µs, max_per_file_from_linter: 1.639µs, exclude: 541ns, diff: 536ns, severity-rules: 453ns, sort_results: 414ns, skip_files: 405ns, path_prefixer: 230ns
INFO [runner] linters took 5.541844945s with stages: goanalysis_metalinter: 5.495077059s
utils_linux.go:129:9: gid declared but not used (typecheck)
        for _, gid := range p.User.AdditionalGids {
               ^
utils_linux.go:133:3: rl declared but not used (typecheck)
                rl, err := createLibContainerRlimit(rlimit)
                ^
libcontainer/integration/utils_test.go:14:2: "syscall" imported but not used (typecheck)
        "syscall"
        ^
INFO File cache stats: 2 entries of total size 17.1KiB
INFO Memory: 67 samples, avg is 228.5MB, max is 410.4MB
INFO Execution took 6.536389745s
Code example or link to a public repository

I've listed the code above, and the repo is https://github.com/opencontainers/runc.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions