Files
gosec/analyzers/form_parsing_limits_internal_test.go
T
Cosmin Cojocar 7210bac169 fix(analyzers): avoid SSA dependency cycle blowups in issue #1555 paths (#1559)
Route redirect dependency checks through the cycle-safe
dependencyChecker instead of raw recursive valueDependsOn traversal.
This ensures Phi-cycle graphs terminate quickly and avoids recursive
work amplification that can look like hangs on large/generated
codebases.

Also remove the nil fallback in dependencyChecker.dependsOn so all
analyzer paths consistently use cycle-aware logic.

Add regression tests covering raw valueDependsOn behavior on:

Phi cycle without target (must return false)
Phi cycle with target path (must return true)
Self-referential Phi node (must return false)

Signed-off-by: Cosmin Cojocar <cosmin@cojocar.ch>
2026-02-28 10:47:40 +01:00

93 lines
2.1 KiB
Go

package analyzers
import (
"go/constant"
"go/types"
"testing"
"golang.org/x/tools/go/ssa"
)
func TestDependencyCheckerHandlesPhiCycleWithoutTarget(t *testing.T) {
t.Parallel()
checker := newDependencyChecker()
target := ssa.NewConst(constant.MakeInt64(42), types.Typ[types.Int])
phiA := &ssa.Phi{}
phiB := &ssa.Phi{}
phiA.Edges = []ssa.Value{phiB}
phiB.Edges = []ssa.Value{phiA}
if checker.dependsOn(phiA, target) {
t.Fatal("expected false for cycle without target dependency")
}
}
func TestDependencyCheckerFindsTargetInPhiCycle(t *testing.T) {
t.Parallel()
checker := newDependencyChecker()
target := ssa.NewConst(constant.MakeInt64(7), types.Typ[types.Int])
phiA := &ssa.Phi{}
phiB := &ssa.Phi{}
phiA.Edges = []ssa.Value{phiB, target}
phiB.Edges = []ssa.Value{phiA}
if !checker.dependsOn(phiA, target) {
t.Fatal("expected true when cycle has a path to target")
}
if !checker.dependsOn(phiA, target) {
t.Fatal("expected stable memoized result on repeated call")
}
}
func TestValueDependsOnHandlesPhiCycleWithoutTarget(t *testing.T) {
t.Parallel()
target := ssa.NewConst(constant.MakeInt64(42), types.Typ[types.Int])
phiA := &ssa.Phi{}
phiB := &ssa.Phi{}
phiA.Edges = []ssa.Value{phiB}
phiB.Edges = []ssa.Value{phiA}
if valueDependsOn(phiA, target, 0) {
t.Fatal("expected false for Phi cycle with no path to target")
}
}
func TestValueDependsOnFindsTargetInPhiCycle(t *testing.T) {
t.Parallel()
target := ssa.NewConst(constant.MakeInt64(7), types.Typ[types.Int])
phiA := &ssa.Phi{}
phiB := &ssa.Phi{}
phiA.Edges = []ssa.Value{phiB, target}
phiB.Edges = []ssa.Value{phiA}
if !valueDependsOn(phiA, target, 0) {
t.Fatal("expected true when cycle has a path to target")
}
if !valueDependsOn(phiA, target, 0) {
t.Fatal("expected stable result on repeated call")
}
}
func TestValueDependsOnSelfReferentialPhi(t *testing.T) {
t.Parallel()
target := ssa.NewConst(constant.MakeInt64(1), types.Typ[types.Int])
phi := &ssa.Phi{}
phi.Edges = []ssa.Value{phi}
if valueDependsOn(phi, target, 0) {
t.Fatal("expected false for self-referential Phi with no path to target")
}
}