Skip to content

test: disable demo.c semi-sparse widen-narrow (known limitation)#181

Open
bjjwwang wants to merge 1 commit intoSVF-tools:masterfrom
bjjwwang:semi-sparse
Open

test: disable demo.c semi-sparse widen-narrow (known limitation)#181
bjjwwang wants to merge 1 commit intoSVF-tools:masterfrom
bjjwwang:semi-sparse

Conversation

@bjjwwang
Copy link
Copy Markdown
Contributor

@bjjwwang bjjwwang commented Apr 9, 2026

Why demo.c semi-sparse widen-narrow fails
Test code:

int demo(int a) {
    if (a >= 10000) return a;
    demo(a+1);
}
int main() {
    int result = demo(0);
    svf_assert(result == 10000);  // fails here
}

Dense derives result ∈ [10000, 10000]; sparse derives [10000, +∞] → assert not verified.

Root cause
In semi-sparse mode, an ArgValVar has exactly one def-site storage slot, but a recursive function needs multiple.

The parameter a of demo (ArgValVar Var23) has its def-site at demo's FunEntry (ICFGNode 1). Two CallPEs write to it:

main → demo(0) writes Var23 = 0
demo → demo(a+1) writes Var23 = a+1 (recursive)
Dense mode: every ICFGNode's trace holds its own ValVar copies. mergeStatesFromPredecessors(cycle_head) uses joinWith, which joins each predecessor's Var23. Widening sees the accumulated [0,1,2,...,+∞] growth; during narrowing, the a >= 10000 cmp branch refinement pulls the upper bound back to 10000.

Sparse mode:

joinWith skips ValVars (AbstractState.cpp:109)
ValVars live only at their def-site (here, FunEntry)
Each recursive iteration's CallPE writes Var23 = a+1 as a strong update, overwriting the previous iteration's value
prev_snapshot is the only place accumulation can live, but its Var23 eventually widens to [0, +∞]
During narrowing, the a >= 10000 cmp branch refinement can only tighten Var23 in a use-site's temporary state; it cannot write back to the def-site (sparse explicitly excludes ValVars from cycle_head joining)
Fundamental conflict:

Sparse's design assumption: "each ValVar has exactly one storage slot (at its def-site)"
Recursion's requirement: "the same ArgValVar simultaneously carries different values for different call contexts" (context-sensitive)
The two are incompatible: one slot cannot hold multiple live values, so they collapse into a single coarse interval. Once that interval widens to +∞, narrowing has no information source left to tighten it

demo.c's recursive ArgValVar needs per-callsite storage which the
semi-sparse model cannot represent (one def-site entry per ValVar,
widening cannot be narrowed back). Dense mode handles this correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@yuleisui
Copy link
Copy Markdown
Collaborator

yuleisui commented Apr 9, 2026

Could we add more tests for loop and recursion handling

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.

2 participants