Skip to content

Handle empty type in incremental SMT2 decision procedure#8907

Open
tautschnig wants to merge 2 commits into
diffblue:developfrom
tautschnig:fix-8077-smt2-incr-empty
Open

Handle empty type in incremental SMT2 decision procedure#8907
tautschnig wants to merge 2 commits into
diffblue:developfrom
tautschnig:fix-8077-smt2-incr-empty

Conversation

@tautschnig
Copy link
Copy Markdown
Collaborator

@tautschnig tautschnig commented Mar 28, 2026

Skip symbols and nondet symbols with empty_typet (void) in gather_dependent_expressions to avoid attempting SMT sort conversion. Add early return in send_function_definition for empty-typed expressions as a defensive measure. Handle equality over empty type in set_to by treating it as vacuously true, matching the behavior of the non-incremental SMT2 backend.

Remove no-new-smt exclusion tag from havoc_slice_checks and memset_null regression tests since they now pass with the incremental SMT2 backend.

Fixes: #8077

  • Each commit message has a non-empty body, explaining why the change was made.
  • 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.

@tautschnig tautschnig self-assigned this Mar 28, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.56%. Comparing base (df24632) to head (38c1921).

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #8907      +/-   ##
===========================================
- Coverage    80.57%   80.56%   -0.01%     
===========================================
  Files         1708     1708              
  Lines       189217   189242      +25     
  Branches        73       73              
===========================================
+ Hits        152460   152467       +7     
- Misses       36757    36775      +18     

☔ 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.

@tautschnig tautschnig marked this pull request as ready for review March 31, 2026 13:29
Copilot AI review requested due to automatic review settings March 31, 2026 13:29
Copy link
Copy Markdown

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 incremental SMT2 backend crashes caused by empty_typet (void) appearing in expressions that the solver attempts to convert to SMT sorts. It aligns the incremental backend’s behavior with the legacy/non-incremental SMT2 path for equality over empty types and re-enables previously excluded regression tests.

Changes:

  • Skip empty-typed symbols/nondet symbols when gathering dependent expressions to avoid attempting SMT sort conversion.
  • Add a defensive early return to avoid declaring SMT functions for empty-typed symbols.
  • Treat equality over empty type as vacuously true in set_to, mirroring the non-incremental SMT2 backend behavior; re-enable affected regression tests.

Reviewed changes

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

File Description
src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp Avoid SMT sort conversion / declarations for empty_typet and short-circuit == over empty type in set_to.
regression/cbmc/memset_null/test.desc Remove no-new-smt exclusion tag now that incremental SMT2 passes the test.
regression/cbmc/havoc_slice_checks/test.desc Remove no-new-smt exclusion tag now that incremental SMT2 passes the test.

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

tautschnig and others added 2 commits May 27, 2026 10:50
is_zero_width(const typet &, const namespacet &) was a file-static
helper in src/solvers/smt2/smt2_conv.cpp. The predicate is generic
('does this type have effective width of zero bits?') and not
specific to the non-incremental SMT2 backend; the incremental SMT2
backend will need exactly the same predicate to detect empty-typed
expressions correctly without re-treading the same struct/union/
struct-tag/union-tag/array recursion. Move the function to
src/util/pointer_offset_size.{h,cpp} alongside its semantic
neighbours pointer_offset_size and pointer_offset_bits, drop the
'static' qualifier on the original definition, and remove the
duplicate body from smt2_conv.cpp.

No functional change. smt2_conv.cpp continues to call is_zero_width
through the shared header (which it already includes); other
back-ends and util-level call sites can now do the same.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Skip zero-width-typed leaves (typically void) in
gather_dependent_expressions so that we never attempt to call
convert_type_to_smt_sort on them, which would hit
UNIMPLEMENTED_FEATURE. Handle the only top-level consumer that
could legitimately involve such a leaf -- equality of two
zero-width-typed operands -- by short-circuiting set_to: for
value == true the equality is vacuously satisfied (no command
emitted); for value == false we send `(assert false)` directly.
This matches the end-to-end behaviour of the non-incremental SMT2
backend, which converts equal_exprt over a zero-width type to
true_exprt and then negates.

Both filter sites use the shared is_zero_width predicate (now
exposed via util/pointer_offset_size.h) rather than a narrow
ID_empty check, so they stay correct even if struct_encoding's
pre-pass ever stops normalising other zero-width forms.

The set_to short-circuit handles only the top-level equality.
Nested cases such as and_exprt{equal_exprt{x_void, y_void}, other}
would still reach convert_expr_to_smt and trip
UNIMPLEMENTED_FEATURE; CBMC's GOTO programs do not produce such
nested shapes today, but pushing the short-circuit into the
equal_exprt overload of convert_expr_to_smt (mirroring
smt2_conv.cpp's structure more closely) is left as a follow-up.

Add a focused unit test in
unit/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp
covering both set_to(equal_exprt{void_x, void_y}, true) (no extra
commands sent) and set_to(..., false) (a single `(assert false)`).

Remove the no-new-smt exclusion tag from havoc_slice_checks and
memset_null regression tests since they now pass with the
incremental SMT2 backend.

Fixes: diffblue#8077

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for empty types is not yet implemented in incremental smt2 decision procedure

4 participants