Skip to content

Move the property pre-check to cfg-extraction; prune under no-runtime-exception (#93) - #108

Open
solid-eureka wants to merge 13 commits into
devfrom
issue-93-precheck-in-cfg-extraction
Open

solid-eureka wants to merge 13 commits into
devfrom
issue-93-precheck-in-cfg-extraction

Conversation

@solid-eureka

@solid-eureka solid-eureka commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Implements the plan from #93: the static property pre-check moves into cfg-extraction, the check and the static pre-analysis graph share instruction facts, and the graph can prune under no-runtime-exception. It also fixes two walk desyncs that came up on the way.

It needs the matching cfg-extraction branch issue-93-precheck-in-cfg-extraction.

Changes

Step 1: the pre-check lives in cfg-extraction

  • The explorer runs cfg-extraction's cfg-extractor-precheck.jar (--precheck-jar, or found next to symbolic-explorer/, or in ../cfg-extraction/build/libs/). The executor no longer contains the check.
  • The SV-COMP archive ships the jar. CI builds it at the cfg-extraction tag pinned in cfg-extraction.ref.

Step 2: shared facts between the check and the graph

  • cfg-extraction marks graph nodes that cannot raise a RuntimeException (cannotRaise), from the check's value analysis.
  • SAGraph turns the exception side of such guards into a dead end.

Step 3: pruning under no-runtime-exception

  • The graph's target points are chosen by property: runtimeExceptionPointIds (the sites that may raise a RuntimeException, plus uncaught[T] of RuntimeException types) under no-runtime-exception.
  • In the harness it is opt-in: svcomp test run --sa-no-runtime-exception.

Walk desyncs

  • Branches inside SWAT's helpers (UtilInstrumented.refEquals) are flagged like callbacks, since their number depends on runtime types. cfg-extraction drops its outdated two-branch model of the helper.
  • cfg-extraction expands Verifier.nondetObject into the factory it calls, as the executor runs it.

Results

SA on, 300 s per task, before and after the changes in this branch:

Suite Before After
valid-assert (978): tasks with an SA desync 73 0
valid-assert: correct verdicts 812 814
sa-soundness (120): correct verdicts 114 115
no-runtime-exception (736) with SA: correct verdicts (not run before) 654, the same as without SA
  • No false SAFE in any run. The remaining false alarms are the mislabelled tasks in Expected verdicts of PieSegment_true and AlbersProjection_true #63.
  • The pre-check gives identical results before and after the move on all 1342 tasks. Its release gate (cfg-extraction scripts/precheck_gate.py) finds 426 + 3 proofs with 0 contradictions.
  • Under no-runtime-exception, SA cuts the queries on solved SAFE tasks by a third but solves nothing new at 300 s (the pre-check already proves 426 tasks, and the extractor costs 3 to 6 s per task). That is why it is opt-in.
  • Tests: executor 11025 unit tests and 36 agent specs, explorer tests and cfg-extraction tests pass.

Before merging

  1. CI access to cfg-extraction. The build job needs a secret CFG_EXTRACTION_TOKEN with read access to the private cfg-extraction repository, or the repository has to become public. Until then CI fails at "Check out cfg-extraction" and skips the test and package jobs.
  2. The tag. cfg-extraction.ref names v0.1.0, which does not exist yet.
  3. A license for cfg-extraction, since its code now ships in the public archive.

Note

This branch is based on niklas/dev, so the PR also contains its six commits that are not in dev yet (string encodings and Int2BvLifting, Z3 5.3.1 in the harness, --search-order, --prefer-short-strings). e9dec3d (char codes lifted without modulo) may overlap with #99.

🤖 Generated with Claude Code

solid-eureka and others added 12 commits October 23, 2026 10:19
Char codes are bounded by 0xFFFF (Java chars), and chars widened to int are lifted too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
indexOf of a char searches the char itself, code points are split over bit-vectors,
and literals with surrogates are built char by char.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The harness requirements still pinned z3-solver 4.14.1, so the explorer ran on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bit-vector inputs under ubv_to_int (string indices, from arguments) get Integer stand-ins,
and the model is mapped back to the inputs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DFS stays the default. coverage tries branch sides no trace took yet first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Off by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The check moved to cfg-extraction; the explorer runs its cfg-extractor-precheck.jar
(--precheck-jar) and the executor no longer contains it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI builds it from cfg-extraction at the tag in cfg-extraction.ref.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A phantom guard marked cannotRaise by the extractor leads to a dead node on its exception side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The graph's target points are chosen by property: runtimeExceptionPointIds under
no-runtime-exception. Opt-in in the harness (--sa-no-runtime-exception).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
How many branches refEquals takes depends on runtime types, so the graph has none of them;
the walk holds its place instead of falling out of step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cfg-extraction is public now, and v0.1.0 (the tag cfg-extraction.ref names) exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant