3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-15 03:25:43 +00:00

Fix debug-only well-sorted traversal freeing temporary assertions (#10067)

The Ubuntu `python make - MT` job was failing in unit tests because the
debug-time well-sorted check could invalidate freshly constructed
assertion expressions during solver entry. This surfaced as crashes in
`theory_dl` and `seq_rewriter`, not as logic bugs in those tests.

- **Root cause**
- `is_well_sorted` traversed the input through a temporary
`expr_ref`/`subterms` wrapper.
- For freshly built assertions passed directly into `assert_expr`, that
temporary ownership could drop the last refcount during validation and
free the AST before the solver used it.

- **Change**
- Reworked the traversal in `src/ast/well_sorted.cpp` to walk raw
`expr*` nodes explicitly.
- The checker now validates subterms without taking transient ownership
of the asserted expression.

- **Effect**
  - Debug validation remains intact.
- Temporary formulas survive the well-sorted check, so assertion-time
validation no longer corrupts the caller’s AST.

- **Representative change**
  ```cpp
  ptr_vector<expr> todo;
  expr_mark visited;
  todo.push_back(e);
  while (!todo.empty()) {
      expr* term = todo.back();
      todo.pop_back();
      if (visited.is_marked(term))
          continue;
      visited.mark(term, true);
      if (is_app(term)) {
          for (expr* arg : *to_app(term))
              if (!visited.is_marked(arg))
                  todo.push_back(arg);
          check_app(to_app(term));
      }
      else if (is_var(term)) {
          check_var(to_var(term));
      }
      else if (is_quantifier(term)) {
          check_quantifier(to_quantifier(term));
      }
  }
  ```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot 2026-07-07 13:26:44 -07:00 committed by GitHub
parent 22c779c77c
commit 165a4a42bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -36,13 +36,27 @@ struct well_sorted_proc {
well_sorted_proc(ast_manager & m):m(m), m_error(false) {}
void check(expr* e) {
for (auto term : subterms::ground(expr_ref(e, m))) {
if (is_app(term))
ptr_vector<expr> todo;
expr_mark visited;
todo.push_back(e);
while (!todo.empty()) {
expr* term = todo.back();
todo.pop_back();
if (visited.is_marked(term))
continue;
visited.mark(term, true);
if (is_app(term)) {
for (expr* arg : *to_app(term))
if (!visited.is_marked(arg))
todo.push_back(arg);
check_app(to_app(term));
else if (is_var(term))
}
else if (is_var(term)) {
check_var(to_var(term));
else if (is_quantifier(term))
}
else if (is_quantifier(term)) {
check_quantifier(to_quantifier(term));
}
}
}
@ -119,4 +133,3 @@ bool is_well_sorted(ast_manager const & m, expr * n) {
return !p.m_error;
}