Skip to content

Comments

Fix array refinement: use actual SAT model values in get()#8842

Open
tautschnig wants to merge 2 commits intodiffblue:developfrom
tautschnig:arrays/refine-get
Open

Fix array refinement: use actual SAT model values in get()#8842
tautschnig wants to merge 2 commits intodiffblue:developfrom
tautschnig:arrays/refine-get

Conversation

@tautschnig
Copy link
Collaborator

Two bugs prevented the array refinement loop from detecting spurious counterexamples:

  1. boolbvt::get() for non-symbol expressions (e.g., array index expressions like a[i]) fell through to prop_conv_solvert::get() which symbolically evaluated sub-expressions. For with-expressions, this symbolic evaluation produced the 'correct' value, masking inconsistencies in the actual SAT model. Fix: when an expression is in the bitvector cache (i.e., it was converted to SAT variables), return the actual model value via bv_get().

  2. freeze_lazy_constraints() only froze the symbols appearing in lazy constraints, but not the intermediate variables created by convert(). When the refinement loop later called convert() on a violated constraint, MiniSat crashed because some variables had been eliminated. Fix: pre-convert and freeze the full constraint literal during freeze_lazy_constraints().

These fixes resolve Array_UF4 and Array_UF8 which were marked as KNOWNBUG.

Co-authored-by: Kiro

  • Each commit message has a non-empty body, explaining why the change was made.
  • n/a Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • n/a White-space or formatting changes outside the feature-related changed lines are in commits of their own.

Copilot AI review requested due to automatic review settings February 24, 2026 14:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes two bugs in the array refinement mechanism that prevented detection of spurious counterexamples. The first bug caused boolbvt::get() to symbolically evaluate sub-expressions instead of returning actual SAT model values for expressions in the bitvector cache. The second bug caused MiniSat crashes during refinement because freeze_lazy_constraints() didn't freeze intermediate variables created by convert().

Changes:

  • Modified boolbvt::get() to return actual model values via bv_get() when expressions are in the bitvector cache
  • Updated freeze_lazy_constraints() to pre-convert and freeze the full constraint literal along with intermediate variables
  • Changed Array_UF4 and Array_UF8 test statuses from KNOWNBUG to CORE

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/solvers/flattening/boolbv_get.cpp Added logic to return actual SAT model values for cached bitvector expressions instead of symbolic evaluation
src/solvers/refinement/refine_arrays.cpp Added constraint literal conversion and freezing to prevent variable elimination during refinement
regression/cbmc/Array_UF4/test.desc Changed test status from KNOWNBUG to CORE
regression/cbmc/Array_UF8/test.desc Changed test status from KNOWNBUG to CORE

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Feb 24, 2026

Codecov Report

❌ Patch coverage is 56.52174% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.00%. Comparing base (708e3fe) to head (6ff2ce4).

Files with missing lines Patch % Lines
src/solvers/flattening/boolbv_get.cpp 50.00% 8 Missing ⚠️
src/solvers/refinement/refine_arrays.cpp 71.42% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #8842   +/-   ##
========================================
  Coverage    80.00%   80.00%           
========================================
  Files         1700     1700           
  Lines       188252   188271   +19     
  Branches        73       73           
========================================
+ Hits        150613   150630   +17     
- Misses       37639    37641    +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kroening
Copy link
Collaborator

What bugs me a bit about item 1. is that the behaviour of ::get depends on caching decisions.

@tautschnig
Copy link
Collaborator Author

What bugs me a bit about item 1. is that the behaviour of ::get depends on caching decisions.

I don't know whether I'd use the term "caching decisions" here - we, after all, "cache" everything that we convert, which, in absence of refinement, is everything. With refinement, it's more of a "refinement" decision rather than a "caching" decision I'd say?

@kroening
Copy link
Collaborator

I don't know whether I'd use the term "caching decisions" here - we, after all, "cache" everything that we convert, which, in absence of refinement, is everything. With refinement, it's more of a "refinement" decision rather than a "caching" decision I'd say?

Indeed we do now -- however, we may not wish to do so in the future, and hence, I would rather not promise this feature to users of ::get. The documentation should likely limit the arguments of ::get to be symbol/index/member. It would likely be better for the refinement procedure to use a different way to get the value of expressions beyond that.

Two bugs prevented the array refinement loop from detecting spurious
counterexamples:

1. boolbvt::get() for non-symbol expressions (e.g., array index
   expressions like a[i]) fell through to prop_conv_solvert::get()
   which symbolically evaluated sub-expressions. For with-expressions,
   this symbolic evaluation produced the 'correct' value, masking
   inconsistencies in the actual SAT model. Fix: when an expression
   is in the bitvector cache (i.e., it was converted to SAT
   variables), return the actual model value via bv_get().

2. freeze_lazy_constraints() only froze the symbols appearing in lazy
   constraints, but not the intermediate variables created by
   convert(). When the refinement loop later called convert() on a
   violated constraint, MiniSat crashed because some variables had
   been eliminated. Fix: pre-convert and freeze the full constraint
   literal during freeze_lazy_constraints().

These fixes resolve Array_UF4 and Array_UF8 which were marked as
KNOWNBUG.

Co-authored-by: Kiro
get() should not have its behaviour depend on whether an expression was
previously converted (cached in bv_cache). Instead, add a dedicated
get_value() method to boolbvt that checks the bitvector cache before
falling back to recursive evaluation. Use get_value() in
arrays_overapproximated() so that the refinement loop reads actual SAT
model values for converted expressions (e.g., array index expressions)
rather than symbolically evaluating with-expressions, which can mask
inconsistencies in the SAT model.

Co-authored-by: Kiro
@tautschnig
Copy link
Collaborator Author

tautschnig commented Feb 24, 2026

Indeed we do now -- however, we may not wish to do so in the future, and hence, I would rather not promise this feature to users of ::get. The documentation should likely limit the arguments of ::get to be symbol/index/member. It would likely be better for the refinement procedure to use a different way to get the value of expressions beyond that.

Added a second commit to implement this. (And revert the prior use of ::get.)

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.

3 participants