Skip to content

Ignore min_length of a constant index into an array - #4974

Open
srivatsansamraj wants to merge 3 commits into
model-checking:mainfrom
srivatsansamraj:constant-index-min-length
Open

srivatsansamraj wants to merge 3 commits into
model-checking:mainfrom
srivatsansamraj:constant-index-min-length

Conversation

@srivatsansamraj

@srivatsansamraj srivatsansamraj commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

codegen_constant_index asserted length >= min_length for arrays, following the MIR documentation, which says min_length is the exact length for arrays. GVN does not keep that: it rewrites an Index with a known value into ConstantIndex { offset, min_length: offset + 1 } without comparing it with the array length. For C[10] on a 5-element array, the bounds check becomes assert(const false) and the unreachable access after it becomes C[10 of 11], so Kani aborted at compile time (#2732). rustc uses mir-opt-level 2 whenever opt-level is above 0, so a crate with opt-level = 1 in its dev profile reached this with plain cargo kani.

rustc's codegen ignores min_length (rustc_codegen_ssa/src/mir/place.rs), and so does Kani's slice arm. This ignores it for arrays too and removes the parameter that becomes unused.

The issue's program now reports the always-failing bounds check instead of aborting. Kani emits that check as assert then assume, so the access after it is unreachable; were such an access reached, CBMC's array_bounds check would fail. With --cbmc-args --no-assumptions, test.array_bounds.1 goes from SUCCESS to FAILURE.

The new test expected/issue-2732 (-Zmir-opt-level=2) calls the issue's function directly, expecting the bounds-check failure, and behind a branch that is never taken, expecting it unreachable. It panics on main.

Resolves #2732

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

@srivatsansamraj
srivatsansamraj requested review from a team as code owners October 5, 2026 21:09
@srivatsansamraj

Copy link
Copy Markdown
Contributor Author

@CYJ904 @Tianshu-Huang @wodex1nhaoIeng @acearyanarun for review. At the same optimisation level, rustc can rewrite an array index that is always out of bounds into a form that broke an assertion inside Kani, so the compiler aborted. Kani now ignores that field the way rustc's own codegen does, and the out-of-bounds check is reported as an ordinary failure. The standard-library runs never hit this, so their numbers don't change.

@github-actions github-actions Bot added Z-EndToEndBenchCI Tag a PR to run benchmark CI Z-CompilerBenchCI Tag a PR to run benchmark CI labels Oct 5, 2026
@srivatsansamraj
srivatsansamraj force-pushed the constant-index-min-length branch from 6f24d88 to 7af26c8 Compare October 9, 2026 16:52
@feliperodri feliperodri self-assigned this Oct 22, 2026

@Tianshu-Huang Tianshu-Huang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, just one comment update

@feliperodri feliperodri added [C] Bug This is a bug. Something isn't working. [F] Crash Kani crashed Z-Autoharness Issue related to autoharness subcommand labels Nov 6, 2026
@feliperodri feliperodri added this to the Autoharness milestone Nov 6, 2026
@feliperodri feliperodri removed the Z-Autoharness Issue related to autoharness subcommand label Nov 6, 2026
@feliperodri feliperodri removed this from the Autoharness milestone Nov 6, 2026
@feliperodri
feliperodri requested a balanced review from Copilot November 6, 2026 18:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

1 open issue
What changed in this PR

Fixes Kani codegen for MIR ConstantIndex on arrays by ignoring min_length (which can become inconsistent after GVN at -Zmir-opt-level=2), preventing compile-time aborts and ensuring out-of-bounds checks are reported as expected.

Changes:

  • Update array ConstantIndex codegen to ignore min_length and drop the now-unused parameter.
  • Add a regression test for issue #2732 and its expected output at -Zmir-opt-level=2.
  • Keep slice handling consistent with rustc by not relying on min_length.
File Description
tests/​expected/​issue-2732/​issue_2732.rs Adds a regression test harness covering always-failing and unreachable out-of-bounds indexing.
tests/​expected/​issue-2732/​issue_2732.expected Captures expected Kani results (FAILURE and UNREACHABLE) for the new regression test.
kani-compiler/​src/​codegen_cprover_gotoc/​codegen/​place.rs Ignores min_length for array ConstantIndex and removes the parameter from codegen.

Review effort: Lite

// Like rustc's codegen, ignore `min_length`: it can exceed `length` after a bounds
// check that always fails, where GVN turns `a[i]` into `a[i of i+1]`. An
// out-of-bounds index that is reached fails CBMC's array bounds check.
let idx = if from_end { length - offset } else { offset };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 3d531c8bd: the index uses wrapping_sub, so an out-of-bounds index reaches CBMC's bounds check instead of panicking.

@feliperodri feliperodri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Dropping the length >= min_length assert follows rustc's codegen, and the explanation of the always-failing bounds check is clear.

Before merge:

  1. length - offset can panic in the compiler when from_end is set and offset > length, on a path behind an always-failing bounds check. Use checked_sub (or saturating_sub) and handle the unreachable case explicitly.
  2. Nine jobs are cancelled. Please re-run them.

GVN rewrites an `Index` with a known value into `ConstantIndex { offset,
min_length: offset + 1 }` without comparing it with the array length, so
for `C[10]` on a 5-element array the `length >= min_length` assertion in
`codegen_constant_index` aborted Kani at `-Zmir-opt-level=2` (model-checking#2732).
Like rustc's codegen, Kani now ignores `min_length` for arrays and drops
the unused parameter; an out-of-bounds index that is reached fails CBMC's
array bounds check.
With `min_length` ignored, an offset from the end can exceed the array
length on the same paths that are never taken, and `length - offset`
would then panic in the compiler. A wrapping subtraction gives an
out-of-bounds index instead, which CBMC's bounds check reports if the
access is reached.
@srivatsansamraj
srivatsansamraj force-pushed the constant-index-min-length branch from a5244bd to 3d531c8 Compare November 7, 2026 06:21

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[C] Bug This is a bug. Something isn't working. [F] Crash Kani crashed Z-CompilerBenchCI Tag a PR to run benchmark CI Z-EndToEndBenchCI Tag a PR to run benchmark CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ice: unconditional panic (array index out of bounds) assertion failed: length >= min_length

4 participants