• Stars
    star
    118
  • Rank 290,544 (Top 6 %)
  • Language
    Go
  • License
    MIT License
  • Created about 4 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

exportloopref

An analyzer that finds exporting pointers for loop variables. Pin them all!

PkgGoDev Go Report Card Coverage Status Release

What's this?

Sample problem code from: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/simple/simple.go

package main

func main() {
	var intArray [4]*int
	var intSlice []*int
	var intRef *int
	var intStr struct{ x *int }

	println("loop expecting 10, 11, 12, 13")
	for i, p := range []int{10, 11, 12, 13} {
		printp(&p)                      // not a diagnostic
		intSlice = append(intSlice, &p) // want "exporting a pointer for the loop variable p"
		intArray[i] = &p                // want "exporting a pointer for the loop variable p"
		if i%2 == 0 {
			intRef = &p   // want "exporting a pointer for the loop variable p"
			intStr.x = &p // want "exporting a pointer for the loop variable p"
		}
		var vStr struct{ x *int }
		var vArray [4]*int
		var v *int
		if i%2 == 0 {
			v = &p         // not a diagnostic (x is local variable)
			vArray[1] = &p // not a diagnostic (x is local variable)
			vStr.x = &p
		}
		_ = v
	}

	println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
	for _, p := range intSlice {
		printp(p)
	}
	println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
	for _, p := range intArray {
		printp(p)
	}
	println(`captured value expecting "12" but "13"`)
	printp(intRef)
}

func printp(p *int) {
	println(*p)
}

In Go, the p variable in the above loops is actually a single variable. So in many case (like the above), using it makes for us annoying bugs.

You can find them with exportloopref, and fix it.

package main

func main() {
	var intArray [4]*int
	var intSlice []*int
	var intRef *int
	var intStr struct{ x *int }

	println("loop expecting 10, 11, 12, 13")
	for i, p := range []int{10, 11, 12, 13} {
    p := p                          // FIX variable into the local variable
		printp(&p)
		intSlice = append(intSlice, &p) 
		intArray[i] = &p
		if i%2 == 0 {
			intRef = &p
			intStr.x = &p
		}
		var vStr struct{ x *int }
		var vArray [4]*int
		var v *int
		if i%2 == 0 {
			v = &p
			vArray[1] = &p
			vStr.x = &p
		}
		_ = v
	}

	println(`slice expecting "10, 11, 12, 13"`)
	for _, p := range intSlice {
		printp(p)
	}
	println(`array expecting "10, 11, 12, 13"`)
	for _, p := range intArray {
		printp(p)
	}
	println(`captured value expecting "12"`)
	printp(intRef)
}

func printp(p *int) {
	println(*p)
}

ref: https://github.com/kyoh86/exportloopref/blob/main/testdata/src/fixed/fixed.go

Sensing policy

I want to make exportloopref as accurately as possible. So some cases of lints will be false-negative.

e.g.

var s Foo
for _, p := range []int{10, 11, 12, 13} {
  s.Bar(&p) // If s stores the pointer, it will be bug.
}

If you want to report all of lints (with some false-positives), you should use looppointer.

Known false negatives

Case 1: pass the pointer to function to export.

Case 2: pass the pointer to local variable, and export it.

package main

type List []*int

func (l *List) AppendP(p *int) {
	*l = append(*l, p)
}

func main() {
	var slice []*int
	list := List{}

	println("loop expect exporting 10, 11, 12, 13")
	for _, v := range []int{10, 11, 12, 13} {
		list.AppendP(&v) // Case 1: wanted "exporting a pointer for the loop variable v", but cannot be found

		p := &v                  // p is the local variable
		slice = append(slice, p) // Case 2: wanted "exporting a pointer for the loop variable v", but cannot be found
	}

	println(`slice expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
	for _, p := range slice {
		printp(p)
	}
	println(`array expecting "10, 11, 12, 13" but "13, 13, 13, 13"`)
	for _, p := range ([]*int)(list) {
		printp(p)
	}
}

func printp(p *int) {
	println(*p)
}

Install

go:

$ go get github.com/kyoh86/exportloopref/cmd/exportloopref

homebrew:

$ brew install kyoh86/tap/exportloopref

gordon:

$ gordon install kyoh86/exportloopref

Usage

exportloopref [-flag] [package]

Flags

Flag Description
-V print version and exit
-all no effect (deprecated)
-c int display offending line with this many lines of context (default -1)
-cpuprofile string write CPU profile to this file
-debug string debug flags, any subset of "fpstv"
-fix apply all suggested fixes
-flags print analyzer flags in JSON
-json emit JSON output
-memprofile string write memory profile to this file
-source no effect (deprecated)
-tags string no effect (deprecated)
-trace string write trace log to this file
-v no effect (deprecated)

LICENSE

MIT License

This is distributed under the MIT License.

More Repositories

1

richgo

Enrich `go test` outputs with text decorations.
Go
831
star
2

scopelint

scopelint checks for unpinned variables in go programs
Go
115
star
3

looppointer

An analyzer that checks for pointers to enclosing loop variables.
Go
38
star
4

momiji

๐Ÿ My color scheme for vim/iTerm2, "momiji" that means Japanese "autumn leaves"๐Ÿ‚
Vim Script
37
star
5

gogh

GO GitHub project manager
Go
29
star
6

vim-ripgrep

A plugin for Vim8/Neovim to search text by ripgrep (rg) asynchronously
Vim Script
28
star
7

xdg

Light weight helper functions in golang to get config, data and cache files according to the XDG Base Directory Specification.
Go
18
star
8

gordon

Go
15
star
9

vim-editerm

Shell
14
star
10

telescope-windows.nvim

Lua
13
star
11

denops-ollama.vim

TypeScript
13
star
12

climbdir.nvim

Lua
11
star
13

gitstat.nvim

A lua plugin for neovim that shows git-status on the top of the editor.
Lua
9
star
14

go-docbase

A Go library for accessing the Docbase API v1/v2
Go
7
star
15

git-statuses

finds local git repositories and show statuses of them
Go
7
star
16

ddu-source-git_log

ddu.vim source collects commit log by using `git log` command
TypeScript
6
star
17

git-vertag

A tool to manage version-tag with the semantic versioning specification.
Go
6
star
18

ddu-filter-converter_hl_dir

ddu.vim converter that highlights directory path of file-like items.
TypeScript
6
star
19

vim-jsonl

Syntax file for JSON Lines on vim/Neovim
Vim Script
6
star
20

zenn-auto-publish-action

JavaScript
5
star
21

vim-docbase

Vim Script
5
star
22

curtain.nvim

Vim Script
5
star
23

git-vertag-action

Dockerfile
5
star
24

csv2xlsx

Go
5
star
25

git-branches

Retrieve the list of branches with last commit author
Go
4
star
26

backgroundfile.nvim

A neovim plugin to open a file in background (hidden floatwin).
Lua
4
star
27

markdown-image.nvim

Markdownใซ็ฝฎใ‹ใ‚ŒใŸ็”ปๅƒใ‚’ใ€้ฉๅˆ‡ใชๅ ดๆ‰€ใซ้…็ฝฎใ—็›ดใ—ใฆใ€ ใใ“ใธใฎใƒชใƒณใ‚ฏใซ็ฝฎใๆ›ใˆใฆใใ‚Œใ‚‹neovimใƒ—ใƒฉใ‚ฐใ‚คใƒณ
Lua
4
star
28

go-spdx

The package parses SPDX license expression strings describing license terms.
Go
4
star
29

telescope-gogh.nvim

Lua
3
star
30

goimportssw

Shorthand for `gofmt -s -w $1 && goimports -w $1`
Shell
2
star
31

zshist

Go
2
star
32

git-prompt

Go
2
star
33

ddu-source-git_branch

ddu.vim source shows branches in the repository
TypeScript
2
star
34

ddu-source-github

A source for ddu.vim to manipulate GitHub
TypeScript
2
star
35

gigamoji

Go
2
star
36

nvim-minimal

Shell
2
star
37

telescope-zenn.nvim

Lua
2
star
38

inkdrop.nvim

A neovim client to access inkdrop
TypeScript
2
star
39

go-check-action

Go
2
star
40

bdelete-buffers.nvim

A vim plugin to enhance to close buffers
Lua
1
star
41

vim-beedle

Vim Script
1
star
42

delete-buffers.nvim

1
star
43

ddu-source-zenn_dev

ddu.vim source collects articles in the repository for zenn.dev.
TypeScript
1
star
44

ddu-source-git_diff_tree

ddu.vim source collects files in the commit
TypeScript
1
star
45

unload-buffers.nvim

A Neovim plugin to enhance to close buffers
Lua
1
star
46

notifail

Go
1
star
47

pyenv-upgrade

Go
1
star
48

vim-packload

Vim Script
1
star
49

nolint

Go
1
star
50

ddu-source-quickfix_history

Quickfix history source for ddu.vim
TypeScript
1
star
51

dotfiles

all of me in the computer
Lua
1
star
52

denops-zenn_dev.vim

TypeScript
1
star