File and Lines
internal/agent/nil_deref_check.go lines 183-206 (clearNilRiskOnErrorCheck)
Problem
When if err != nil is encountered, clearNilRiskOnErrorCheck clears ALL entries in the nilRisk map, regardless of which error variable was actually checked. This causes false negatives when multiple error variables exist and only some are checked.
Trigger Scenario
func example() {
a, err1 := getA() // "a" marked as nil-risk (associated with err1)
b, err2 := getB() // "b" marked as nil-risk (associated with err2)
if err1 != nil { // checks err1, but clears BOTH "a" and "b"
return
}
// err2 was NEVER checked, so b could still be nil
fmt.Println(b.Field) // FALSE NEGATIVE: b dereferenced but not flagged
}
Execution trace:
- After
a, err1 := getA(): nilRisk = {"a": pos}
- After
b, err2 := getB(): nilRisk = {"a": pos, "b": pos}
- At
if err1 != nil: clearNilRiskOnErrorCheck deletes ALL entries
- At
fmt.Println(b.Field): detectNilDeref finds no entry for "b" → no warning
Expected vs Actual Behavior
- Expected: Only variables associated with
err1 should be cleared when err1 is checked. Variables associated with err2 should remain tracked.
- Actual: ALL nil-risk variables are cleared regardless of which error variable is checked.
The comment at lines 200-201 says "we only clear those whose position is before this if-statement, but since ast.Inspect visits in order, all existing entries qualify" — but the real issue is that clearing is not specific to the error variable being checked. The nilRisk map (map[string]int) tracks variable name → position but does not track which error variable each non-error variable is associated with.
Severity
HIGH — Silent false negatives for dangerous nil-pointer dereference patterns. Multi-error-variable patterns are common in non-trivial Go code.
Fix Suggestion
Change nilRisk to track the association between non-error variables and their error variable (e.g., map[string]string for varName → errVarName). Then clearNilRiskOnErrorCheck should only clear entries associated with the specific error variable being checked.
File and Lines
internal/agent/nil_deref_check.golines 183-206 (clearNilRiskOnErrorCheck)Problem
When
if err != nilis encountered,clearNilRiskOnErrorCheckclears ALL entries in thenilRiskmap, regardless of which error variable was actually checked. This causes false negatives when multiple error variables exist and only some are checked.Trigger Scenario
Execution trace:
a, err1 := getA():nilRisk = {"a": pos}b, err2 := getB():nilRisk = {"a": pos, "b": pos}if err1 != nil:clearNilRiskOnErrorCheckdeletes ALL entriesfmt.Println(b.Field):detectNilDereffinds no entry for "b" → no warningExpected vs Actual Behavior
err1should be cleared whenerr1is checked. Variables associated witherr2should remain tracked.The comment at lines 200-201 says "we only clear those whose position is before this if-statement, but since ast.Inspect visits in order, all existing entries qualify" — but the real issue is that clearing is not specific to the error variable being checked. The
nilRiskmap (map[string]int) tracks variable name → position but does not track which error variable each non-error variable is associated with.Severity
HIGH — Silent false negatives for dangerous nil-pointer dereference patterns. Multi-error-variable patterns are common in non-trivial Go code.
Fix Suggestion
Change
nilRiskto track the association between non-error variables and their error variable (e.g.,map[string]stringfor varName → errVarName). ThenclearNilRiskOnErrorCheckshould only clear entries associated with the specific error variable being checked.