Skip to content

Challenge 27: Verify Arc/Weak safety in alloc::sync with Kani#587

Open
v3risec wants to merge 1 commit intomodel-checking:mainfrom
v3risec:challenge-27-arc
Open

Challenge 27: Verify Arc/Weak safety in alloc::sync with Kani#587
v3risec wants to merge 1 commit intomodel-checking:mainfrom
v3risec:challenge-27-arc

Conversation

@v3risec
Copy link
Copy Markdown

@v3risec v3risec commented Apr 21, 2026

Summary

This PR adds Kani-based verification artifacts for Arc/Weak safety in library/alloc/src/sync.rs for Challenge 27.

The change introduces:

  • safety contracts for all required unsafe Arc/Weak functions listed in the challenge
  • proof harness modules under #[cfg(kani)] for those unsafe functions and a broad safe-function subset
  • atomic-aware contracts and harnesses that check pointer layout/alignment/allocation consistency and key strong/weak refcount invariants
  • shared helper-based construction for nondeterministic unsized slice inputs, so Arc<[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 27)

Coverage: 12 / 12 (100%)

Verified set includes:

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

Safe functions (Challenge 27 list)

Stable passing coverage: 54 / 58 (93.1%)

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

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

Allocation

  • Arc<T>::new
  • Arc<T>::new_uninit
  • Arc<T>::new_zeroed
  • Arc<T>::pin
  • Arc<T>::try_pin
  • Arc<T>::try_new
  • Arc<T>::try_new_uninit
  • Arc<T>::try_new_zeroed
  • Arc<T,A:Allocator>::new_in
  • Arc<T,A:Allocator>::new_uninit_in
  • Arc<T,A:Allocator>::new_zeroed_in
  • Arc<T,A:Allocator>::new_cyclic_in
  • Arc<T,A:Allocator>::pin_in
  • Arc<T,A:Allocator>::try_pin_in
  • Arc<T,A:Allocator>::try_new_in
  • Arc<T,A:Allocator>::try_new_uninit_in
  • Arc<T,A:Allocator>::try_new_zeroed_in
  • Arc<T,A:Allocator>::try_unwrap
  • Arc<T,A:Allocator>::into_inner
  • Arc<T:?Sized,A:Allocator>::into_inner_with_allocator

Slice

  • Arc<[T]>::new_uninit_slice
  • Arc<[T]>::new_zeroed_slice
  • Arc<[T]>::into_array
  • Arc<[T],A:Allocator>::new_uninit_slice_in
  • Arc<[T],A:Allocator>::new_zeroed_slice_in
  • ArcFromSlice<T: Copy>::from_slice

Conversion and pointer

  • Arc<T:?Sized,A:Allocator>::into_raw_with_allocator
  • Arc<T:?Sized,A:Allocator>::as_ptr
  • Arc<T:?Sized,A:Allocator>::inner
  • Arc<T:?Sized,A:Allocator>::from_box_in
  • Clone<T:?Sized, A:Allocator>::clone for Arc
  • Arc<T:?Sized+CloneToUninit, A:Allocator+Clone>::make_mut
  • Arc<T:?Sized, A:Allocator>::get_mut
  • Drop<T:?Sized, A:Allocator>::drop for Arc
  • Arc<dyn Any+Send+Sync,A:Allocator>::downcast

Weak and trait-related operations

  • 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

Default and conversions

  • Default<T:Default>::default
  • Default<core::ffi::CStr>::default
  • Default<[T]>::default
  • From<&str>::from
  • From<Vec<T,A:Allocator+Clone>>::from
  • From<Arc<str>>::from

UniqueArc / UniqueArcUninit and traits

  • UniqueArcUninit<T:?Sized, A:Allocator>::new
  • UniqueArcUninit<T:?Sized, A:Allocator>::data_ptr
  • Drop<T:?Sized, A:Allocator>::drop for UniqueArcUninit
  • UniqueArc<T:?Sized,A:Allocator>::into_arc
  • UniqueArc<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 UniqueArc

Not yet listed as standalone harness targets (4/58)

  • Default<str>::default
  • ArcFromSlice<T: Clone>::from_slice
  • TryFrom<Arc<[T],A:Allocator>>::try_from
  • ToArcSlice<T, I>::to_arc_slice

Current Criteria Met

  • Required unsafe functions covered: all 12/12 required unsafe functions in Challenge 27 are annotated with contracts and verified.
  • Safe-function threshold met: 54/58 safe functions are in the stable passing set (93.1%), exceeding the challenge threshold of at least 75%.
  • Challenge scope allowances respected: generic T is instantiated with representative concrete types allowed by the challenge, 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. Contracts for unsafe functions
  • Attach kani::requires preconditions for pointer validity, alignment soundness, same-allocation checks, and refcount well-formedness.
  • Use atomic-aware conditions where needed for Arc strong/weak counters.
  • Attach postconditions and mutation footprints where appropriate for refcount-changing operations.
  1. Harness-backed behavioral checks
  • Add dedicated #[kani::proof] / #[kani::proof_for_contract] modules for required unsafe functions and safe-function coverage targets.
  • Cover ownership-state-sensitive APIs by constructing representative states such as unique ownership, shared strong ownership, and externally held weak references.
  1. Helper-based unsized generalization
  • Introduce shared helper functions for nondeterministic vector/slice construction and reuse them across Arc<[T]> / Weak<[T]> harnesses.
  • Use those helpers to exercise ?Sized slice cases without duplicating setup logic across harnesses.
  1. Challenge alignment
  • Keep all verification code under cfg(kani) so normal std behavior is unchanged.
  • Target the Challenge 27 success criteria directly: full required unsafe coverage and safe coverage above the required threshold.

Scope assumptions (per challenge allowance)

  • Harnesses instantiate representative concrete types including signed/unsigned widths (i8..i128, u8..u128), bool, (), arrays, vectors, slices, str, CStr, and trait objects (dyn Any, dyn Any + Send + Sync where required by the API).
  • Allocator coverage is limited to Global.

Note on data races

This PR uses Kani proof harnesses in the current single-threaded verification setting. As a result, these proofs do not model true concurrent interleavings between multiple threads.

What is verified here is that the Arc / Weak APIs covered by these harnesses are memory-safe under the explored single-threaded executions, including pointer validity, alignment/allocation consistency, and key strong/weak reference-count invariants.

Verification

All passing harnesses listed in this report pass locally with the current Kani setup used for this repository.

Resolves #383

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 21, 2026 16:11
@v3risec v3risec changed the title alloc: add Arc/Weak Kani proofs for challenge 27 Challenge 27: Verify Arc/Weak safety in alloc::sync with Kani Apr 21, 2026
@feliperodri feliperodri requested a review from Copilot April 21, 2026 17:33
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 added the Challenge Used to tag a challenge label Apr 21, 2026
@v3risec
Copy link
Copy Markdown
Author

v3risec commented Apr 22, 2026

I would like to report on the two CI failures from this PR.

For Kani / Verify std library using autoharness (macos-latest) (pull_request), the check reported two failing harnesses:

  • sync::verify_2459::harness_arc_make_mut_vec_u32_shared
  • slice::ascii::verify::check_is_ascii

Both failures were reported as CBMC timed out.

a6e03b281c8cef10bfc160b16e3b33ad f0e03c26c556e25a073d25d5a240ef33

Of these two, slice::ascii::verify::check_is_ascii was not introduced by this PR; it is a pre-existing harness in the repository.

For sync::verify_2459::harness_arc_make_mut_vec_u32_shared, I was able to verify it successfully in my local environment, and I did not reproduce the CBMC timed out behavior there.

f3b2baf227b17df34d0bdd34765d9b89

For the other failing check, Kani / Kani List (pull_request), the CI error message appears to indicate an infrastructure issue. From the message, it looks like the CI worker may have run into a disk-space / log-writing problem, which caused the command to terminate.

34cd6d390120e1f0a362ded663a1317a

For reference, my local verification environment is:

  • CPU: 2 x Intel(R) Xeon(R) Gold 6230R CPU @ 2.10GHz
  • Cores / threads: 52 physical cores / 104 logical CPUs
  • Memory: 125 GiB RAM
  • OS: Ubuntu 24.04.1 LTS
  • Kernel: Linux 6.11.0-26-generic
  • Kani: 0.65.0, repo-pinned commit 415ca503aea80fd4c4c4819ad4770b744f1bc3a1
  • CBMC: 6.8.0 (cbmc-6.8.0)
  • Rust: rustc 1.92.0-nightly (b6f0945 2025-10-08)
  • Host: x86_64-unknown-linux-gnu
  • LLVM: 21.1.2

Based on the current evidence, my impression is that these failures are more likely related to CI environment instability or resource constraints than to a semantic issue in the harnesses introduced by this PR. Would it make sense to investigate whether the CI runners are hitting memory limits, and if so, whether the memory budget or other CI resource constraints for these Kani jobs should be adjusted?

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 27: Verify atomically reference-counted Cell implementation

3 participants