Fix ICE on pattern types over wide pointers under -Z valid-value-checks - #4856
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Existing comments still incorrectly state that all pattern types have scalar ABIs.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
What changed in this PR
Prevents -Z valid-value-checks from crashing on wide-pointer pattern types.
Changes:
- Returns an unsupported-check error for non-scalar pattern types.
- Adds an allocation regression test and expected diagnostic.
| File | Description |
|---|---|
kani-compiler/src/kani_middle/transform/check_values.rs |
Replaces the scalar-ABI assertion with graceful rejection. |
tests/expected/valid-value-checks/fat_pointer_pattern.rs |
Adds the allocation regression case. |
tests/expected/valid-value-checks/fat_pointer_pattern.expected |
Captures the expected unsupported-check result. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
feliperodri
left a comment
There was a problem hiding this comment.
Thanks for picking this up. The crash is gone, but the fix trades it for a spurious failure. Every allocation reaches NonNull<[u8]>, so reporting it as unsupported makes every allocating program fail verification under -Z valid-value-checks. The new test shows it: a correct Box program is expected to FAIL. The flag stays unusable on real code, which was #4829's impact.
The pass already knows how to check wide pointers. try_from_ty reads the first scalar of a ScalarPair, which is the data pointer and its valid range, and that's how &[u8] and *const [u8] are handled today. The !null of *const [u8] is !null is exactly that range, so accepting ScalarPair here is enough:
- if !matches!(layout.value_repr, ValueRepr::Scalar(..)) {
+ if !matches!(layout.value_repr, ValueRepr::Scalar(..) | ValueRepr::ScalarPair { .. }) {I tried it: Box::new, Vec::push, and a non-null NonNull<[u8]> transmute all verify, and a transmute with a null data pointer is still caught as Undefined Behavior: Invalid value of type NonNull<[u8]>. The other 10 tests using -Z valid-value-checks are unchanged.
What would flip this to approval: that change, with fat_pointer_pattern expecting SUCCESSFUL, plus a harness with a null data pointer that must FAIL, so the test shows the requirement is enforced and not skipped. Box<dyn Debug> and Rc<str> then stop at other, pre-existing unsupported constructs (fmt::rt, copy_nonoverlapping on *const u8). Those are separate issues, not this PR's.
feliperodri
left a comment
There was a problem hiding this comment.
Thanks for the quick turnaround — this addresses everything from my earlier review. Accepting ScalarPair lets allocating code verify under -Z valid-value-checks. null_data_pointer shows the !null requirement is enforced rather than skipped. Unknown layouts now return an unsupported-check error instead of asserting, so the pass can't ICE here. The note on why assert_eq!(nn.len(), 3) is there is helpful too.
I checked it locally, merged with current main. All 10 valid-value-checks tests pass. Vec::push and NonNull::from(&a[..]) verify, and a NonNull<[u8]> whose data pointer is kani::any() is correctly reported as invalid.
One non-blocking note: only the first scalar of the pair is checked. For NonNull<dyn Trait> that means a null vtable isn't caught, the same as for &dyn Trait today. That gap is #3738, not this PR.
16722a9
…del-checking#4923) Pass `--harness-timeout 5m` to `script-based-pre/cargo_autoharness_fmt_impls`, as the other autoharness tests (`bounded`, `bounds`, `byte_str`, `c_str`, `formatter`, `wtf8`) already do. **Why.** On the macOS x86_64 runners (`regression (macos-15-intel)`), the `LowerExp`, `UpperExp` and `Pointer` harnesses of this test take 40–60 s, right at `kani autoharness`'s default `--harness-timeout` of 60 s. When one of them times out, CBMC reports `CBMC timed out` instead of the expected failure, the test's `Failed Checks: "lower exp"` / `"upper exp"` / `"pointer"` line is missing, and the test fails. The same harnesses take about 10 s on Linux. **Evidence.** I went through the logs of the `regression (macos-15-intel)` jobs between 2026-09-28 and 2026-09-30. 33 of them failed. This test failed in all 33, with 1–3 of those three harnesses timing out each time, and in 32 of them it was the only failing test. The one exception, model-checking#4903's merge-queue push run, also had `cargo_autoharness_wtf8`'s `len` harness time out, at 5 m. On main pushes alone, the job failed 7 times out of 12 on 2026-09-30. The failures are independent of the changes under test: - Today's automated toolchain upgrade, model-checking#4917: [run 36663872235](https://github.com/model-checking/kani/actions/runs/36663872235/job/109726991201) (`LowExp`, `UpExp`, `Ptr` timed out; every other regression job passed) - `main` pushes: [36654469481](https://github.com/model-checking/kani/actions/runs/36654469481/job/109695682794), [36656240395](https://github.com/model-checking/kani/actions/runs/36656240395/job/109701095388), [36657849257](https://github.com/model-checking/kani/actions/runs/36657849257/job/109705923680), [36659060566](https://github.com/model-checking/kani/actions/runs/36659060566/job/109709545862), [36670355214](https://github.com/model-checking/kani/actions/runs/36670355214/job/109743820142), [36674524840](https://github.com/model-checking/kani/actions/runs/36674524840/job/109756493668) - Merge queue: model-checking#4895 [36650793954](https://github.com/model-checking/kani/actions/runs/36650793954/job/109684194253), model-checking#4896 [36650908721](https://github.com/model-checking/kani/actions/runs/36650908721/job/109684568489), model-checking#4809 [36654883143](https://github.com/model-checking/kani/actions/runs/36654883143/job/109696960300), model-checking#4848 [36663305755](https://github.com/model-checking/kani/actions/runs/36663305755/job/109722546228), model-checking#4903 [36667236036](https://github.com/model-checking/kani/actions/runs/36667236036/job/109734401431), model-checking#4856 [36670723600](https://github.com/model-checking/kani/actions/runs/36670723600/job/109744937944), model-checking#4881 [36596324505](https://github.com/model-checking/kani/actions/runs/36596324505/job/109502054372), model-checking#4882 [36612997613](https://github.com/model-checking/kani/actions/runs/36612997613/job/109558873539) - Pull requests: model-checking#4875 [36427316996](https://github.com/model-checking/kani/actions/runs/36427316996/job/109072277288), model-checking#4895 [36443349794](https://github.com/model-checking/kani/actions/runs/36443349794/job/108999214513), model-checking#4771 [36620184925](https://github.com/model-checking/kani/actions/runs/36620184925/job/109677883533) The runner image version (`20260819.586`) was the same in passing and failing runs. **Manual testing.** Locally the three harnesses take about 10 s each. Running the test with `--harness-timeout 3s` reproduces the CI failure exactly: the same three harnesses time out, their `Failed Checks` lines are missing, and the summary still reports 9 failures. With this change, `cargo run -p compiletest -- --suite script-based-pre --mode exec cargo_autoharness_fmt_impls` passes. If the macOS Intel runner gets much slower, a longer timeout alone may not be enough; making these three harnesses cheaper would be the next step. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>

ty_validity_per_offset asserted that a pattern type has a Scalar layout. NonNull<[u8]>'s field is pattern_type!(*const [u8] is !null), a wide pointer with a ScalarPair layout, and every allocation reaches it, so -Z valid-value-checks ICE'd on any program using Box/Vec/String.
Accept ScalarPair alongside Scalar. try_from_ty already takes the first scalar's valid_range for a pair, which is the data pointer's !null, the same way &[u8] is checked. Any other layout is reported as unsupported instead of asserted on.
The regression test uses the issue's reproducer: Box::new now verifies, and a second harness that transmutes a null data pointer into NonNull<[u8]> fails with Invalid value of type NonNull<[u8]>, so the check is enforced rather than skipped.
Resolves #4829
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.