Skip to content

Commit cc41410

Browse files
fix: prevent false positive recursion detection in tests (Fixes #564)
Problem: When building goenv AUR package with goenv-installed Go (not system Go), all exec tests fail with 'infinite recursion detected' error. This happens because _GOENV_EXEC_ACTIVE=1 is inherited from parent shell when tests run under goenv-managed Go. Root Cause: Simple boolean check (if env var != '') creates false positive when tests inherit _GOENV_EXEC_ACTIVE from parent shell. Pattern: User has goenv Go active → runs 'paru -S goenv' → build runs 'make check' → 'go test' calls goenv exec internally → recursion guard finds inherited env var → FALSE POSITIVE. Solution: Changed recursion guard from simple boolean check to PID-based detection. Now checks if env var value equals parent PID (os.Getppid()), indicating actual shim → exec → shim → exec recursion chain, not just inherited environment. Also added os.Unsetenv('_GOENV_EXEC_ACTIVE') in test setup as defensive measure. Testing: All exec tests now pass (TestExecCommand with 9 subtests, TestExecEnvironmentVariables, TestExecWithShims). PID-based approach prevents false positives while still catching real infinite recursion.
1 parent 4abf4c6 commit cc41410

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

cmd/shims/exec.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,13 @@ func runExec(cmd *cobra.Command, args []string) error {
6363
args = args[1:]
6464
}
6565

66-
// Recursion guard: detect if we're being called from a shim that we spawned
66+
// Recursion guard: detect if we're being called from a shim that we spawned.
67+
// We only treat this as recursion if the value equals our parent PID, indicating
68+
// we were spawned by another goenv exec (shim → exec → shim → exec).
69+
// This avoids false positives when running tests under goenv-managed Go.
6770
const recursionEnvVar = "_GOENV_EXEC_ACTIVE"
68-
if os.Getenv(recursionEnvVar) != "" {
71+
parentPIDStr := fmt.Sprintf("%d", os.Getppid())
72+
if os.Getenv(recursionEnvVar) == parentPIDStr {
6973
return fmt.Errorf("goenv: infinite recursion detected — shim is calling goenv exec again. Run 'goenv rehash' to regenerate shims")
7074
}
7175

@@ -312,8 +316,9 @@ func runExec(cmd *cobra.Command, args []string) error {
312316
}
313317

314318
// Execute with the modified environment
315-
// Set recursion guard so shims don't re-enter goenv exec
316-
execEnv = setEnvVar(execEnv, recursionEnvVar, "1")
319+
// Set recursion guard so shims don't re-enter goenv exec.
320+
// Use our PID as the value so the child can detect if it's being called recursively.
321+
execEnv = setEnvVar(execEnv, recursionEnvVar, fmt.Sprintf("%d", os.Getpid()))
317322
execCmd := exec.Command(commandPath, commandArgs...)
318323
execCmd.Env = execEnv
319324
execCmd.Stdin = os.Stdin

cmd/shims/exec_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ func TestExecCommand(t *testing.T) {
108108
t.Setenv(utils.GoenvEnvVarVersion.String(), "")
109109
os.Unsetenv("GOENV_VERSION")
110110

111+
// Clear _GOENV_EXEC_ACTIVE to avoid false recursion detection
112+
// This can be set when tests are run via goenv-managed Go (e.g., during package builds)
113+
os.Unsetenv("_GOENV_EXEC_ACTIVE")
114+
111115
// Setup test versions
112116
for _, version := range tt.setupVersions {
113117
cmdtest.CreateTestVersion(t, testRoot, version)

0 commit comments

Comments
 (0)