Skip to content

Challenge 26: verify Rc/Weak safety in alloc::rc with Kani#582

Draft
v3risec wants to merge 4 commits intomodel-checking:mainfrom
v3risec:challenge-26-rc
Draft

Challenge 26: verify Rc/Weak safety in alloc::rc with Kani#582
v3risec wants to merge 4 commits intomodel-checking:mainfrom
v3risec:challenge-26-rc

Conversation

@v3risec
Copy link
Copy Markdown

@v3risec v3risec commented Apr 2, 2026

Summary

This PR adds Kani-based verification artifacts for Rc/Weak safety in library/alloc/src/rc.rs for Challenge 26.

The change introduces:

  • proof harness modules under #[cfg(kani)] for both required unsafe functions and a broad safe-function subset
  • contracts/harnesses that check pointer layout/alignment/allocation consistency and key reference-count invariants
  • shared helper-based construction for nondeterministic unsized slice inputs, so Rc<[T]>/Weak<[T]> paths can be exercised in a reusable way

No non-verification runtime behavior is changed in normal builds.

Verification Coverage Report

Unsafe functions (required by Challenge 26)

Coverage: 12 / 12 (100%)

Verified set includes:

  • Rc<mem::MaybeUninit<T>,A>::assume_init
  • Rc<[mem::MaybeUninit<T>],A>::assume_init
  • Rc<T:?Sized>::from_raw
  • Rc<T:?Sized>::increment_strong_count
  • Rc<T:?Sized>::decrement_strong_count
  • Rc<T:?Sized,A:Allocator>::from_raw_in
  • Rc<T:?Sized,A:Allocator>::increment_strong_count_in
  • Rc<T:?Sized,A:Allocator>::decrement_strong_count_in
  • Rc<T:?Sized,A:Allocator>::get_mut_unchecked
  • Rc<dyn Any,A:Allocator>::downcast_unchecked
  • Weak<T:?Sized>::from_raw
  • Weak<T:?Sized,A:Allocator>::from_raw_in

Safe functions (Challenge 26 list)

Coverage: 51 / 54 (94.4%)

This exceeds the challenge threshold (>= 75%).

Covered safe functions (51/54), grouped by API category:

Allocation

  • Rc<T>::new
  • Rc<T>::new_uninit
  • Rc<T>::new_zeroed
  • Rc<T>::try_new
  • Rc<T>::try_new_uninit
  • Rc<T>::try_new_zeroed
  • Rc<T>::pin
  • Rc<T,A:Allocator>::new_uninit_in
  • Rc<T,A:Allocator>::new_zeroed_in
  • Rc<T,A:Allocator>::new_cyclic_in
  • Rc<T,A:Allocator>::try_new_in
  • Rc<T,A:Allocator>::try_new_uninit_in
  • Rc<T,A:Allocator>::try_new_zeroed_in
  • Rc<T,A:Allocator>::pin_in

Slice

  • Rc<[T]>::new_uninit_slice
  • Rc<[T]>::new_zeroed_slice
  • Rc<[T]>::into_array
  • Rc<[T],A:Allocator>::new_uninit_slice_in
  • Rc<[T],A:Allocator>::new_zeroed_slice_in
  • RcFromSlice<T: Copy>::from_slice
  • ToRcSlice<T, I>::to_rc_slice

Conversion and pointer

  • Rc<T:?Sized, A:Allocator>::inner
  • Rc<T:?Sized, A:Allocator>::into_inner_with_allocator
  • Rc<T,A:Allocator>::try_unwrap
  • Rc<T:?Sized,A:Allocator>::as_ptr
  • Rc<T:?Sized,A:Allocator>::get_mut
  • Rc<T:?Sized+CloneToUninit, A:Allocator+Clone>::make_mut
  • Rc<T:?Sized,A:Allocator>::from_box_in
  • Rc<dyn Any,A:Allocator>::downcast

Trait implementations (Rc)

  • Clone<T: ?Sized, A:Allocator>::clone for Rc
  • Drop<T: ?Sized, A:Allocator>::drop for Rc
  • Default<T:Default>::default
  • Default<str>::default
  • From<&str>::from
  • From<Vec<T,A:Allocator>>::from
  • From<Rc<str>>::from

Weak and traits

  • Weak<T:?Sized,A:Allocator>::as_ptr
  • Weak<T:?Sized,A:Allocator>::into_raw_with_allocator
  • Weak<T:?Sized,A:Allocator>::upgrade
  • Weak<T:?Sized,A:Allocator>::inner
  • Drop<T:?Sized, A:Allocator>::drop for Weak

UniqueRc and traits

  • UniqueRc<T:?Sized,A:Allocator>::into_rc
  • UniqueRc<T:?Sized,A:Allocator+Clone>::downgrade
  • Deref<T:?Sized,A:Allocator>::deref
  • DerefMut<T:?Sized,A:Allocator>::deref_mut
  • Drop<T:?Sized, A:Allocator>::drop for UniqueRc
  • UniqueRcUninit<T:?Sized, A:Allocator>::new
  • UniqueRcUninit<T:?Sized, A:Allocator>::data_ptr
  • Drop<T:?Sized, A:Allocator>::drop for UniqueRcUninit

Refcount internals

  • RcInnerPtr::inc_strong
  • RcInnerPtr::inc_weak

Not yet listed as standalone harness targets (3/54):

  • Rc<T:?Sized,A:Allocator>::into_raw_with_allocator
  • RcFromSlice<T: Clone>::from_slice
  • TryFrom<Rc<[T],A:Allocator>>::try_from

Three Criteria Met (Challenge 26)

  • Required unsafe functions covered: All 12/12 required unsafe functions in Challenge 26 are annotated with contracts and verified.
  • Safe-function threshold met: 51/54 safe functions are covered (94.4%), which exceeds the Challenge 26 requirement of at least 75%.
  • Challenge scope allowances respected: Generic T is instantiated with allowed representative concrete types, and allocator-focused proofs are limited to standard-library allocator scope (Global).

Approach

The verification strategy combines contracts for unsafe entry points with executable proof harnesses:

  1. Contract for unsafe functions
  • Attach kani::requires preconditions for pointer validity, alignment soundness, same-allocation checks, and refcount well-formedness.
  • Attach postconditions where appropriate (kani::ensures) and mutation footprints (kani::modifies) for refcount-changing operations.
  1. Harness-backed behavioral checks
  • Add dedicated #[kani::proof] and #[kani::proof_for_contract()] modules for each required unsafe function and safe function coverage.
  1. Helper-based unsized generalization
  • Introduce shared helper functions for nondeterministic vector/slice setup and reuse them across harnesses that target ?Sized slice-based functions.
  • Use the helpers to exercise unsized slice cases through Rc<[T]>/Weak<[T]> constructions without duplicating per-harness setup logic.
  1. Challenge alignment
  • Keep all verification code under cfg(kani) so normal std behavior is unchanged.
  • Target Challenge 26 success criteria directly: full required unsafe coverage + safe coverage above threshold.

Scope assumptions (per challenge allowance)

  • Harnesses instantiate representative concrete types, including signed/unsigned widths (i8..i128, u8..u128), bool, (), arrays/slices, str, String, and trait objects (dyn Any).
  • Allocator coverage is limited to Global (both explicit Rc<_, Global> / Weak<_, Global> and default Rc/Weak aliases).

Verification

All harnesses in this PR pass locally with Kani 0.65.

Resolves #382

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

@v3risec v3risec requested a review from a team as a code owner April 2, 2026 18:17
@feliperodri
Copy link
Copy Markdown

You should use macros to reduce code duplication. It'll also make review easier.

@feliperodri feliperodri added the Challenge Used to tag a challenge label Apr 2, 2026
@feliperodri feliperodri requested a review from Copilot April 2, 2026 19:16
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

@feliperodri feliperodri requested a review from Copilot April 9, 2026 03:17
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot wasn't able to review any files in this pull request.

@v3risec v3risec marked this pull request as draft April 9, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Challenge Used to tag a challenge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Challenge 26: Verify reference-counted Cell implementation

4 participants