Skip to content

Challenge 29: Verify safety of Box functions#573

Open
Samuelsills wants to merge 2 commits intomodel-checking:mainfrom
Samuelsills:challenge-29-box
Open

Challenge 29: Verify safety of Box functions#573
Samuelsills wants to merge 2 commits intomodel-checking:mainfrom
Samuelsills:challenge-29-box

Conversation

@Samuelsills
Copy link
Copy Markdown

Summary

Add Kani proof harnesses for Box functions specified in Challenge #29:

Unsafe (9/9 — all required):

  • assume_init (single + slice), from_raw, from_non_null, from_raw_in, from_non_null_in, downcast_unchecked (Any, Any+Send, Any+Send+Sync)

Safe (34/43 — 79%, exceeds 75% threshold):

  • Allocation: new_in, try_new_in, try_new_uninit_in, try_new_zeroed_in
  • Slices: new_uninit_slice, new_zeroed_slice, try_new_uninit_slice, try_new_zeroed_slice, into_array
  • Conversion: into_boxed_slice, write, into_non_null, into_raw_with_allocator, into_non_null_with_allocator, into_unique, leak, into_pin
  • Traits: drop, default (i32, str), clone (T, str), from_slice, from (&str), from (Box->Box<[u8]>), try_from (slice->array)
  • Downcasting: downcast (Any x3, Error x3)

All harnesses verified locally with Kani.

Resolves #526

Samuelsills and others added 2 commits March 26, 2026 23:28
Add Kani proof harnesses for Box functions specified in Challenge model-checking#29:
9 unsafe functions (assume_init, from_raw, from_non_null, from_raw_in,
from_non_null_in, downcast_unchecked x3) and 34 safe functions covering
allocation, conversion, cloning, downcasting, and trait implementations.
Exceeds the 75% safe function threshold (34/43 = 79%).
Resolves model-checking#526

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Samuelsills Samuelsills marked this pull request as ready for review March 27, 2026 08:30
@Samuelsills Samuelsills requested a review from a team as a code owner March 27, 2026 08:30
@Samuelsills
Copy link
Copy Markdown
Author

Verification Coverage Report

Unsafe Functions (9/9 — 100% ✅)

assume_init (single), assume_init (slice), from_raw, from_non_null, from_raw_in, from_non_null_in, downcast_unchecked (Any), downcast_unchecked (Any+Send), downcast_unchecked (Any+Send+Sync)

Safe Functions with Unsafe Code (34/43 — 79%, exceeds 75% threshold ✅)

Allocation: new_in, try_new_in, try_new_uninit_in, try_new_zeroed_in
Slices: new_uninit_slice, new_zeroed_slice, try_new_uninit_slice, try_new_zeroed_slice, into_array
Conversion: into_boxed_slice, write, into_non_null, into_raw_with_allocator, into_non_null_with_allocator, into_unique, leak, into_pin
Traits: drop, default (i32), default (str), clone, clone (str), from_slice, from (&str), from (Box→Box<[u8]>), try_from
Downcasting: downcast (Any ×3), downcast (Error ×3)

Total: 43 harnesses (9 unsafe + 34 safe)

UBs Checked

  • ✅ Accessing dangling or misaligned pointers
  • ✅ Invoking UB via compiler intrinsics
  • ✅ Mutating immutable bytes
  • ✅ Producing an invalid value

Verification Approach

  • Tool: Kani Rust Verifier
  • Generic T limited to primitive types (i32) per spec allowance

@feliperodri feliperodri added the Challenge Used to tag a challenge label Mar 29, 2026
@feliperodri feliperodri requested a review from Copilot March 31, 2026 22:19
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.

Pull request overview

Adds Kani proof harnesses to alloc::boxed to model-check safety contracts and key behaviors of Box APIs as part of Challenge #29 (“Safety of boxed”), including required unsafe APIs and a threshold of safe APIs.

Changes:

  • Introduces a #[cfg(kani)] verify module containing Kani proof harnesses for 9 required unsafe Box functions.
  • Adds Kani proof harnesses for 34 safe Box functions across allocation, slice utilities, conversions, traits, and downcasting.
  • Includes downcast proofs for Any/Error trait objects and their Send/Sync variants.

Comment on lines +2308 to +2309
let r: Result<Box<[i32; 3]>, _> = b.try_into();
assert!(r.is_ok());
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

verify_into_array is currently exercising TryInto (b.try_into()) rather than the Box<[T]>::into_array API (which returns Option<Box<[T; N]>>). This means the into_array method isn’t actually being verified here and the proof largely duplicates verify_try_from_slice_to_array. Update this harness to call b.into_array::<3>() (and assert is_some() / contents) so it covers the intended function.

Suggested change
let r: Result<Box<[i32; 3]>, _> = b.try_into();
assert!(r.is_ok());
let r = b.into_array::<3>();
assert!(r.is_some());
let r = r.unwrap();
assert!(r[0] == 1 && r[1] == 2 && r[2] == 3);

Copilot uses AI. Check for mistakes.
Comment on lines +2164 to +2172
#[cfg(kani)]
#[unstable(feature = "kani", issue = "none")]
mod verify {
use core::any::Any;
use core::kani;
use core::mem::MaybeUninit;

use crate::alloc::Global;
use crate::boxed::Box;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This #[cfg(kani)] verification module calls APIs like Box::new, Box::new_uninit, and Box::new_uninit_slice, which are all #[cfg(not(no_global_oom_handling))] in this file. As written, enabling cfg(kani) alongside no_global_oom_handling will fail to compile. Consider gating the module (or the affected proofs) with #[cfg(not(no_global_oom_handling))], or rewriting the harnesses to only use fallible/allocator-based constructors that are available under no_global_oom_handling.

Copilot uses AI. Check for mistakes.
Comment on lines +2448 to +2460
fn verify_downcast_error() {
use core::fmt;
#[derive(Debug)]
struct MyError;
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MyError")
}
}
impl super::error::Error for MyError {}
let e: Box<dyn super::error::Error> = Box::new(MyError);
let d = e.downcast::<MyError>();
assert!(d.is_ok());
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

MyError (and its Display/Error impls) is duplicated across the three verify_downcast_error* proofs. To reduce repetition and keep these harnesses easier to maintain, consider defining MyError once in the module (or a small helper) and reusing it in all three proofs.

Copilot uses AI. Check for mistakes.
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 29: Safety of boxed

3 participants