Skip to content

deep-exit: detect exit-triggering flag usage#1544

Merged
chavacava merged 5 commits intomgechev:masterfrom
uloamaka:feature/add-go-lib-flag-Parse-call-exclusion
Oct 23, 2025
Merged

deep-exit: detect exit-triggering flag usage#1544
chavacava merged 5 commits intomgechev:masterfrom
uloamaka:feature/add-go-lib-flag-Parse-call-exclusion

Conversation

@uloamaka
Copy link
Copy Markdown
Contributor

@uloamaka uloamaka commented Oct 9, 2025

This PR resolves #1523,
Packages using flag.ExitOnError or flag.Parse() can exit on invalid flags or --help, which violates the principle of reusability the deep-exit rule enforces.

This PR enhances the deep-exit rule to detect indirect program termination caused by the Go flag package.

Specifically, it adds checks for:

  • flag.NewFlagSet created with flag.ExitOnError
  • Calls to flag.Parse() outside of main() or init()

These usages can terminate programs unexpectedly, reducing reusability of packages that expose such functions.

Updates:

  • testdata/deep_exit.go
  • I added tests

Signed-off-by: Godsgift Uloamaka <godsgiftuloamaka235@gmail.com>
@alexandear alexandear changed the title feat: extend deep-exit to detect exit-triggering flag usage deep-exit: detect exit-triggering flag usage Oct 10, 2025
@uloamaka
Copy link
Copy Markdown
Contributor Author

@alexandear Can you please help review this PR.

@alexandear alexandear requested a review from chavacava October 14, 2025 10:26
Comment thread rule/utils.go Outdated
Comment thread rule/utils.go Outdated
Comment thread rule/utils.go Outdated
Comment thread rule/utils.go Outdated
Comment thread rule/utils.go Outdated
Comment thread rule/utils.go
Comment thread rule/utils.go
Comment thread rule/utils.go Outdated
Comment thread cli/main.go
flag.BoolVar(&setExitStatus, "set_exit_status", false, exitStatusUsage)
flag.IntVar(&maxOpenFiles, "max_open_files", 0, maxOpenFilesUsage)
flag.Parse()
flag.Parse() //revive:disable-line:deep-exit
Copy link
Copy Markdown
Collaborator

@chavacava chavacava Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact we disable the rule in our own code makes me think on the pertinence of checking calls to flag.Parse outside the main function.

Copy link
Copy Markdown
Contributor

@ccoVeille ccoVeille Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because the right way to do is to use either this

func main() {

	// (...)
	flag.BoolVar(&setExitStatus, "set_exit_status", false, exitStatusUsage)
	flag.IntVar(&maxOpenFiles, "max_open_files", 0, maxOpenFilesUsage)
	flag.Parse()

	// (...)
}

or this

func main() {
	err := run()
	// (...)
}

func run() error {
	fl := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
	fl.BoolVar(&setExitStatus, "set_exit_status", false, exitStatusUsage)
	fl.IntVar(&maxOpenFiles, "max_open_files", 0, maxOpenFilesUsage)
	err := fl.Parse(os.Args[1:])
	if err != nil {
		return err
	}
	// (...)

	return nil
}

You can take a look at the code I wrote for gh-reaction

But maybe, the error message for flag.Parse should be way clearer, about the fact there is a need to use flag.ContinueOnError

Please note also, that the same code, using flag.NewFlagSet(os.Args[0], flag.ExitOnError) or flag.NewFlagSet(os.Args[0], flag.PanicOnError) should be reported as deep-exit, but it would be a next move, and somehow a niche maybe

EDIT: it's not a niche :P https://github.com/search?q=language%3Ago%20%2Fflag%5C.NewFlagSet.*flag%5C.(Exit%7CPanic)OnError%2F%20-is%3Afork%20-is%3Aarchived&type=code

Comment thread testdata/deep_exit.go Outdated
@chavacava chavacava merged commit 1bc57ac into mgechev:master Oct 23, 2025
10 checks passed
@chavacava
Copy link
Copy Markdown
Collaborator

Thank you @uloamaka for the PR and @alexandear @ccoVeille for the feedback

@alexandear alexandear mentioned this pull request Nov 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

deep-exit: add Go standard library flag.Parse call to default exclusions

4 participants