Skip to content

--export-json: a failed, empty, or partial run can serialize as a clean pass #4731

Description

@ivmat

--export-json is a -Z-gated, currently-undocumented output. Using it as a CI pass/fail
oracle in a standard-library verification effort, we hit several cases where the exported file
does not faithfully represent the run: a run that failed, was skipped, matched nothing, or
wasn't fully measured can be read as a clean, complete pass
by a consumer that trusts the file.

These are reporting-fidelity issues in an unstable output — none changes a verification
verdict, a property status, or Kani's exit code. Grouped below by how each is best fixed.

Driver bugs — pre-existing (predate #4472), surfaced but not caused by --export-json; tracked as two small standalone PRs

A. A filter that matches zero harnesses runs to a completed / 0 failed export.
determine_targets only bails on a missing filter under --exact (metadata.rs:112); the
generic "no harnesses matched" bail lives in print_final_summary (harness_runner.rs:302),
which runs after the export is written — so a filter typo yields Ok([]), a clean-looking
export, and exit 0. Same area, independent of --export-json: print_final_summary
early-returns under --quiet (harness_runner.rs:255) before that bail, so
kani --quiet --harness <typo> skips the "no harnesses matched" error and exits 0.
Fix in determine_targets, before codegen and before any export.

B. --fail-fast drops the harnesses it skipped (#4729).
Root cause: collect::<Result<Vec<_>>>() (harness_runner.rs:105) short-circuits on the first
Err and discards already-completed Ok results. The lost harnesses are then absent from the
per-harness details, and the plain-text summary and SARIF under-report too — not only the JSON.
Fix the collect (#4729), not the reporter.

Deferred to RFC #4727

  • Stale export is never invalidated. A run that reuses an existing --export-json path and
    dies before the write leaves the previous complete-looking file in place. The completeness
    mechanism (atomic temp-file + rename, "file exists ⇒ complete") is a schema/design decision
    specified in RFC RFC: Structured verification results (export-json) #4727, not a writer patch.
  • No leaf-value / semantic validation of the exported file. Pending the RFC's open question
    on shipping a JSON Schema (schemars) vs. a homegrown validator.
  • cbmc_stats parsing is brittle (exact strip_prefix/strip_suffix; a malformed duplicate
    can clobber a valid value; overflow/absence collapse to null). Pending the RFC decision on
    whether CBMC statistics remain in the schema at all.

Schema (with the RFC)

  • harness_id == pretty_name can misattribute across a workspace. pretty_name can collide
    between two crates, so the metadata↔details join can attribute a result to the wrong harness
    (confirmed with a workspace carrying duplicate harness names). Fix: make harness_id
    crate-qualified (mangled_name / crate::pretty) — the consumer-facing id, not only the join.

The paired implementation PR #4732 is closed in favor of this decomposition: the two driver PRs,
the RFC, and crate-qualified harness_id.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions