Skip to content

Fix three constructor-discovery ICEs from the crates.io sweep - #4725

Draft
tautschnig wants to merge 3 commits into
model-checking:mainfrom
tautschnig:ctor-pr-fixes
Draft

Fix three constructor-discovery ICEs from the crates.io sweep#4725
tautschnig wants to merge 3 commits into
model-checking:mainfrom
tautschnig:ctor-pr-fixes

Conversation

@tautschnig

Copy link
Copy Markdown
Member

Stacked on #4717 (--constructor-args); only the last commit is new. Marked draft until #4717 merges.

A top-500 crates.io autoharness sweep (tracking #3832) ICEd in constructor discovery on 12 crates; three root causes:

  1. Item own lifetimes (brotli, sharded-slab): AtomicU8::from_ptr<'a>-style constructors were resolved with the ADT args only — arity mismatch panic.
  2. Lifetime position (regex-automata, gimli, redox_syscall, arc-swap, clap_builder, event-listener, crypto-bigint): impl<'h> Searcher<'h> places the lifetime first, so appending erased lifetimes is insufficient — the argument list is now built positionally against the item's full parent+own generics, rejecting shape mismatches up front (rustc's instantiation panics on kind mismatches rather than returning Err).
  3. Escaping bound regions (async-io, js-sys, quinn-udp, wasm-bindgen): BorrowedFd<'_>-style arguments read from a skipped fn-sig binder panicked the trait solver's dummy-binder wrap; such candidates are rejected as non-generatable.

All 12 crates verified clean with this branch. The constructor regression test gains all three shapes.

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

tautschnig and others added 3 commits August 5, 2026 15:04
A layout niche (rustc_layout_scalar_valid_range, as used by std's NonZero
and core::time::Duration's Nanoseconds field) is a language-level validity
invariant: a value outside the niche is as invalid as a bool holding 3, and
rustc packs enum variants into the invalid patterns. Nondeterministic-value
generation for types without an Arbitrary implementation previously
produced such values, which is unsound in the garbage-in sense and causes
false alarms in every harness generating the type.

After each generated value of a scalar-ABI type whose valid range is
restricted, emit kani::assume(<raw bits> in valid_range), handling wrapping
ranges (NonZero's 1..=0). Sound by construction: no flag or report marker
needed.

Verified on the time crate: fixes the InstantExt/SystemTimeExt
signed_duration_since harnesses (std Duration receivers); the regression
test's covers confirm no over-constraining.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
The top-100 crates.io failure triage (model-checking#3832) showed the largest class of
genuine false alarms is generated receivers violating private type
invariants (e.g. time's Date packs a validated ordinal; raw field synthesis
produces invalid dates, failing every method harness). Under the new opt-in
--constructor-args flag, kani::any::<T> for private-field structs is
synthesized as: generate nondeterministic constructor arguments, call one
of T's public constructors, assume success (switching on the discriminant
for Option<Self>/Result<Self, E> returns), and return the payload.

Constructor search excludes non-public, doc-hidden (commonly _unchecked
variants exported for macros that assert preconditions), unsafe,
zero-argument (single-point coverage; Instant::now() reaches unsupported
clock_gettime), and generic constructors; it prefers Self over Option<Self>
over Result<Self, E> returns, then more arguments over fewer.

The option is opt-in because it under-approximates (only
constructor-reachable values are explored): harnesses are marked "(ctor)"
via new is_ctor_based metadata, with an explanatory note in the summary.

Measured on time-0.3.54: 341 -> 538 verified, 500 -> 315 failures.

Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
Surfaced by a top-500 crates.io autoharness sweep (12 crates affected):

1. Items with their own early-bound lifetimes (AtomicU8::from_ptr<'a>)
   were resolved with the ADT args only, panicking on the arity mismatch
   (brotli, sharded-slab).
2. Lifetime-parameterized impls place lifetimes anywhere in the generics
   order (impl<'h> Searcher<'h> in regex-automata; also gimli,
   redox_syscall, arc-swap, clap_builder, event-listener, crypto-bigint),
   so appending erased lifetimes is not enough: build the argument list
   positionally against the item's full parent+own generics, rejecting
   the constructor when counts or kinds do not fit (rustc's instantiation
   panics on kind mismatches rather than returning Err).
3. Constructor arguments carrying escaping late-bound regions inside ADTs
   (BorrowedFd<'_> in async-io, js-sys, quinn-udp, wasm-bindgen) panicked
   the trait solver's dummy-binder wrap; such arguments are not
   generatable, so reject the candidate up front.

The constructor regression test gains all three shapes.

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

Labels

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.

1 participant