Skip to content

Recognize deferred named recover helpers in goroutinemissingrecover - #50848

Merged
pelikhan merged 4 commits into
mainfrom
copilot/goroutinemissingrecover-fix
Aug 6, 2026
Merged

Recognize deferred named recover helpers in goroutinemissingrecover#50848
pelikhan merged 4 commits into
mainfrom
copilot/goroutinemissingrecover-fix

Conversation

Copilot AI commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

goroutinemissingrecover only accepted a defer whose target is a function literal, so a goroutine deferring a named helper that calls recover() directly was flagged as unprotected — even though the Go spec counts any function called directly by defer as a valid recovery point.

func recoverAndLog() {
	if r := recover(); r != nil {
		log.Printf("recovered: %v", r)
	}
}

go func() {
	defer recoverAndLog() // was flagged; now accepted
	risky()
}()

Changes

  • hasTopLevelRecoverDefer: when the deferred target is not an *ast.FuncLit, resolve it to a *types.Func and run the existing containsRecoverCall check against its body.
  • resolveFuncBody (new): resolves *ast.Ident via TypesInfo.Uses, methods via TypesInfo.Selections, and unwraps generic instantiations (f[T], f[T1, T2]). Returns false for anything not statically resolvable.
  • indexFuncBodies (new): one pass over pass.Files building *types.Func → body (keyed by Origin() so generic instantiations map back to the declaration).
  • Unchanged conservatism: func-valued variables, out-of-package targets, and recover() buried in a nested closure inside the helper are still flagged.
  • Package doc: notes that a deferred named function/method qualifies.

Test fixtures

Added to testdata/src/a/a.go: named helper with recover() and method with recover() (no diagnostic); named helper without recover(), deferred func value, and helper whose recover() is nested in a closure (still flagged).

Note: the fixture package reports pre-existing unused lint findings (every fixture function, old and new, is unreferenced); these are not introduced here.

Copilot AI and others added 2 commits August 6, 2026 12:35
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix misreporting of named recover-helper functions Recognize deferred named recover helpers in goroutinemissingrecover Aug 6, 2026
Copilot AI requested a review from pelikhan August 6, 2026 12:37
@pelikhan
pelikhan marked this pull request as ready for review August 6, 2026 12:44
Copilot AI balanced review requested due to automatic review settings August 6, 2026 12:44
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ failed during design decision gate check.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The analyzer can incorrectly accept helpers where recover() executes through a nested go or defer statement.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Extends goroutinemissingrecover to recognize same-package named recovery helpers and methods.

Changes:

  • Resolves deferred named functions, methods, and generic instantiations.
  • Indexes function bodies for recovery analysis.
  • Adds positive and conservative negative fixtures.
File summaries
File Description
goroutinemissingrecover.go Implements named-helper resolution and analysis.
testdata/src/a/a.go Adds named-helper and method fixtures.
Review details

Suppressed comments (1)

pkg/linters/goroutinemissingrecover/goroutinemissingrecover.go:178

  • The new generic-instantiation paths are not exercised by the fixture: all added accepted calls are non-generic. Please add cases for defer helper[T]() (and preferably a generic-receiver method) so the IndexExpr/IndexListExpr unwrapping and Origin() lookup cannot regress unnoticed.
	case *ast.IndexExpr:
		// Explicit instantiation of a generic function: f[T].
		return resolveFuncBody(unwrapParens(target.X), typesInfo, funcBodies)
	case *ast.IndexListExpr:
		return resolveFuncBody(unwrapParens(target.X), typesInfo, funcBodies)
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

continue
}
if containsRecoverCall(fn.Body, typesInfo) {
if containsRecoverCall(deferredBody, typesInfo) {

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 32 AIC · ⊞ 7.1K
Comment /matt to run again

// Package-qualified function (pkg.Fn) — no selection recorded and the
// body lives in another package, so it cannot be inspected.
return nil, false
case *ast.IndexExpr:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The *ast.IndexExpr and *ast.IndexListExpr branches (generic function instantiations like defer f[T]()) are not covered by any test fixture — a regression here would go undetected.

💡 Suggested test fixture

Add to testdata/src/a/a.go:

func genericRecoverHelper[T any]() {
	if r := recover(); r != nil {
		_ = r
	}
}

func genericRecoverDeferGoroutine() {
	go func() {
		defer genericRecoverHelper[int]()
		panic("oops")
	}()
}

Include a parallel case without recover() to cover the negative path too.

@copilot please address this.

@pelikhan

pelikhan commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

@pelikhan
pelikhan merged commit 1cac677 into main Aug 6, 2026
31 of 33 checks passed
@pelikhan
pelikhan deleted the copilot/goroutinemissingrecover-fix branch August 6, 2026 14:51
Copilot stopped work on behalf of pelikhan due to an error August 6, 2026 14:52
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.86.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

goroutinemissingrecover: defer of a named recover-helper function is misreported as "missing recover"

3 participants