Skip to content

Commit 177a4bb

Browse files
Samuelsillsclaude
andcommitted
Challenge 17: Verify safety of Slice functions
Add Kani proof harnesses for all 37 slice functions specified in Challenge #17, covering 10 unsafe functions and 27 safe abstractions. Resolves #281 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2840898 commit 177a4bb

1 file changed

Lines changed: 372 additions & 0 deletions

File tree

library/core/src/slice/mod.rs

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5508,4 +5508,376 @@ mod verify {
55085508
let mut a: [u8; 100] = kani::any();
55095509
a.reverse();
55105510
}
5511+
5512+
// --- Challenge #17: Slice harnesses ---
5513+
const SLICE_LEN: usize = 5;
5514+
5515+
#[kani::proof]
5516+
fn check_get_unchecked() {
5517+
let arr: [i32; SLICE_LEN] = kani::any();
5518+
let s: &[i32] = &arr;
5519+
let idx: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5520+
let val = unsafe { s.get_unchecked(idx) };
5521+
assert_eq!(*val, arr[idx]);
5522+
}
5523+
5524+
#[kani::proof]
5525+
fn check_get_unchecked_mut() {
5526+
let mut arr: [i32; SLICE_LEN] = kani::any();
5527+
let idx: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5528+
let s: &mut [i32] = &mut arr;
5529+
let val = unsafe { s.get_unchecked_mut(idx) };
5530+
*val = 42;
5531+
assert_eq!(arr[idx], 42);
5532+
}
5533+
5534+
#[kani::proof]
5535+
fn check_swap_unchecked() {
5536+
let mut arr: [i32; SLICE_LEN] = kani::any();
5537+
let a: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5538+
let b: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5539+
let orig_a = arr[a];
5540+
let orig_b = arr[b];
5541+
unsafe { arr.swap_unchecked(a, b) };
5542+
assert_eq!(arr[a], orig_b);
5543+
assert_eq!(arr[b], orig_a);
5544+
}
5545+
5546+
#[kani::proof]
5547+
fn check_as_chunks_unchecked() {
5548+
let arr: [i32; 4] = kani::any();
5549+
let s: &[i32] = &arr;
5550+
let chunks: &[[i32; 2]] = unsafe { s.as_chunks_unchecked::<2>() };
5551+
assert_eq!(chunks.len(), 2);
5552+
assert_eq!(chunks[0][0], arr[0]);
5553+
assert_eq!(chunks[1][1], arr[3]);
5554+
}
5555+
5556+
#[kani::proof]
5557+
fn check_as_chunks_unchecked_mut() {
5558+
let mut arr: [i32; 4] = kani::any();
5559+
let s: &mut [i32] = &mut arr;
5560+
let chunks: &mut [[i32; 2]] = unsafe { s.as_chunks_unchecked_mut::<2>() };
5561+
assert_eq!(chunks.len(), 2);
5562+
chunks[0][0] = 99;
5563+
assert_eq!(arr[0], 99);
5564+
}
5565+
5566+
#[kani::proof]
5567+
fn check_split_at_unchecked() {
5568+
let arr: [i32; SLICE_LEN] = kani::any();
5569+
let s: &[i32] = &arr;
5570+
let mid: usize = kani::any_where(|&m: &usize| m <= SLICE_LEN);
5571+
let (left, right) = unsafe { s.split_at_unchecked(mid) };
5572+
assert_eq!(left.len(), mid);
5573+
assert_eq!(right.len(), SLICE_LEN - mid);
5574+
}
5575+
5576+
#[kani::proof]
5577+
fn check_split_at_mut_unchecked() {
5578+
let mut arr: [i32; SLICE_LEN] = kani::any();
5579+
let mid: usize = kani::any_where(|&m: &usize| m <= SLICE_LEN);
5580+
let s: &mut [i32] = &mut arr;
5581+
let (left, right) = unsafe { s.split_at_mut_unchecked(mid) };
5582+
assert_eq!(left.len(), mid);
5583+
assert_eq!(right.len(), SLICE_LEN - mid);
5584+
}
5585+
5586+
#[kani::proof]
5587+
fn check_get_disjoint_unchecked_mut() {
5588+
let mut arr: [i32; SLICE_LEN] = kani::any();
5589+
let a: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5590+
let b: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5591+
kani::assume(a != b);
5592+
let s: &mut [i32] = &mut arr;
5593+
let [ra, rb] = unsafe { s.get_disjoint_unchecked_mut([a, b]) };
5594+
*ra = 10;
5595+
*rb = 20;
5596+
assert_eq!(arr[a], 10);
5597+
assert_eq!(arr[b], 20);
5598+
}
5599+
5600+
#[kani::proof]
5601+
fn check_first_chunk() {
5602+
let arr: [i32; SLICE_LEN] = kani::any();
5603+
let s: &[i32] = &arr;
5604+
let chunk: Option<&[i32; 3]> = s.first_chunk::<3>();
5605+
assert!(chunk.is_some());
5606+
assert_eq!(chunk.unwrap()[0], arr[0]);
5607+
assert_eq!(chunk.unwrap()[2], arr[2]);
5608+
}
5609+
5610+
#[kani::proof]
5611+
fn check_first_chunk_mut() {
5612+
let mut arr: [i32; SLICE_LEN] = kani::any();
5613+
let s: &mut [i32] = &mut arr;
5614+
let chunk: Option<&mut [i32; 3]> = s.first_chunk_mut::<3>();
5615+
assert!(chunk.is_some());
5616+
chunk.unwrap()[0] = 77;
5617+
assert_eq!(arr[0], 77);
5618+
}
5619+
5620+
#[kani::proof]
5621+
fn check_split_first_chunk() {
5622+
let arr: [i32; SLICE_LEN] = kani::any();
5623+
let s: &[i32] = &arr;
5624+
let result: Option<(&[i32; 2], &[i32])> = s.split_first_chunk::<2>();
5625+
assert!(result.is_some());
5626+
let (head, tail) = result.unwrap();
5627+
assert_eq!(head[0], arr[0]);
5628+
assert_eq!(tail.len(), 3);
5629+
}
5630+
5631+
#[kani::proof]
5632+
fn check_split_first_chunk_mut() {
5633+
let mut arr: [i32; SLICE_LEN] = kani::any();
5634+
let s: &mut [i32] = &mut arr;
5635+
let result: Option<(&mut [i32; 2], &mut [i32])> = s.split_first_chunk_mut::<2>();
5636+
assert!(result.is_some());
5637+
let (head, tail) = result.unwrap();
5638+
head[0] = 55;
5639+
assert_eq!(tail.len(), 3);
5640+
}
5641+
5642+
#[kani::proof]
5643+
fn check_split_last_chunk() {
5644+
let arr: [i32; SLICE_LEN] = kani::any();
5645+
let s: &[i32] = &arr;
5646+
let result: Option<(&[i32], &[i32; 2])> = s.split_last_chunk::<2>();
5647+
assert!(result.is_some());
5648+
let (init, last) = result.unwrap();
5649+
assert_eq!(init.len(), 3);
5650+
assert_eq!(last[1], arr[4]);
5651+
}
5652+
5653+
#[kani::proof]
5654+
fn check_split_last_chunk_mut() {
5655+
let mut arr: [i32; SLICE_LEN] = kani::any();
5656+
let s: &mut [i32] = &mut arr;
5657+
let result: Option<(&mut [i32], &mut [i32; 2])> = s.split_last_chunk_mut::<2>();
5658+
assert!(result.is_some());
5659+
let (_init, last) = result.unwrap();
5660+
last[0] = 88;
5661+
assert_eq!(arr[3], 88);
5662+
}
5663+
5664+
#[kani::proof]
5665+
fn check_last_chunk() {
5666+
let arr: [i32; SLICE_LEN] = kani::any();
5667+
let s: &[i32] = &arr;
5668+
let chunk: Option<&[i32; 3]> = s.last_chunk::<3>();
5669+
assert!(chunk.is_some());
5670+
assert_eq!(chunk.unwrap()[2], arr[4]);
5671+
}
5672+
5673+
#[kani::proof]
5674+
fn check_last_chunk_mut() {
5675+
let mut arr: [i32; SLICE_LEN] = kani::any();
5676+
let s: &mut [i32] = &mut arr;
5677+
let chunk: Option<&mut [i32; 3]> = s.last_chunk_mut::<3>();
5678+
assert!(chunk.is_some());
5679+
chunk.unwrap()[0] = 66;
5680+
assert_eq!(arr[2], 66);
5681+
}
5682+
5683+
#[kani::proof]
5684+
fn check_as_chunks() {
5685+
let arr: [i32; 4] = kani::any();
5686+
let s: &[i32] = &arr;
5687+
let (chunks, remainder) = s.as_chunks::<2>();
5688+
assert_eq!(chunks.len(), 2);
5689+
assert_eq!(remainder.len(), 0);
5690+
assert_eq!(chunks[0][0], arr[0]);
5691+
}
5692+
5693+
#[kani::proof]
5694+
fn check_as_chunks_mut() {
5695+
let mut arr: [i32; 4] = kani::any();
5696+
let s: &mut [i32] = &mut arr;
5697+
let (chunks, remainder) = s.as_chunks_mut::<2>();
5698+
assert_eq!(chunks.len(), 2);
5699+
assert_eq!(remainder.len(), 0);
5700+
chunks[1][1] = 33;
5701+
assert_eq!(arr[3], 33);
5702+
}
5703+
5704+
#[kani::proof]
5705+
fn check_as_rchunks() {
5706+
let arr: [i32; SLICE_LEN] = kani::any();
5707+
let s: &[i32] = &arr;
5708+
let (remainder, chunks) = s.as_rchunks::<2>();
5709+
assert_eq!(chunks.len(), 2);
5710+
assert_eq!(remainder.len(), 1);
5711+
assert_eq!(remainder[0], arr[0]);
5712+
}
5713+
5714+
#[kani::proof]
5715+
fn check_split_at_checked() {
5716+
let arr: [i32; SLICE_LEN] = kani::any();
5717+
let s: &[i32] = &arr;
5718+
let mid: usize = kani::any();
5719+
if mid <= SLICE_LEN {
5720+
let result = s.split_at_checked(mid);
5721+
assert!(result.is_some());
5722+
let (l, r) = result.unwrap();
5723+
assert_eq!(l.len(), mid);
5724+
assert_eq!(r.len(), SLICE_LEN - mid);
5725+
} else {
5726+
assert!(s.split_at_checked(mid).is_none());
5727+
}
5728+
}
5729+
5730+
#[kani::proof]
5731+
fn check_split_at_mut_checked() {
5732+
let mut arr: [i32; SLICE_LEN] = kani::any();
5733+
let mid: usize = kani::any();
5734+
let s: &mut [i32] = &mut arr;
5735+
if mid <= SLICE_LEN {
5736+
let result = s.split_at_mut_checked(mid);
5737+
assert!(result.is_some());
5738+
let (l, r) = result.unwrap();
5739+
assert_eq!(l.len(), mid);
5740+
assert_eq!(r.len(), SLICE_LEN - mid);
5741+
} else {
5742+
let s2: &mut [i32] = &mut arr;
5743+
assert!(s2.split_at_mut_checked(mid).is_none());
5744+
}
5745+
}
5746+
5747+
#[kani::proof]
5748+
fn check_copy_from_slice() {
5749+
let src: [i32; SLICE_LEN] = kani::any();
5750+
let mut dst: [i32; SLICE_LEN] = kani::any();
5751+
dst.copy_from_slice(&src);
5752+
assert_eq!(dst, src);
5753+
}
5754+
5755+
#[kani::proof]
5756+
fn check_copy_within() {
5757+
let mut arr: [i32; SLICE_LEN] = kani::any();
5758+
let src_start: usize = kani::any();
5759+
let src_end: usize = kani::any();
5760+
let dest: usize = kani::any();
5761+
kani::assume(src_start <= src_end);
5762+
kani::assume(src_end <= SLICE_LEN);
5763+
kani::assume(dest <= SLICE_LEN - (src_end - src_start));
5764+
arr.copy_within(src_start..src_end, dest);
5765+
}
5766+
5767+
#[kani::proof]
5768+
fn check_swap_with_slice() {
5769+
let mut a: [i32; SLICE_LEN] = kani::any();
5770+
let mut b: [i32; SLICE_LEN] = kani::any();
5771+
let orig_a = a;
5772+
let orig_b = b;
5773+
a.swap_with_slice(&mut b);
5774+
assert_eq!(a, orig_b);
5775+
assert_eq!(b, orig_a);
5776+
}
5777+
5778+
#[kani::proof]
5779+
#[kani::unwind(6)]
5780+
fn check_binary_search_by() {
5781+
let a: i32 = kani::any();
5782+
let b: i32 = kani::any();
5783+
let c: i32 = kani::any();
5784+
kani::assume(a <= b && b <= c);
5785+
let arr = [a, b, c];
5786+
let target: i32 = kani::any();
5787+
let result = arr.binary_search_by(|probe| probe.cmp(&target));
5788+
match result {
5789+
Ok(idx) => assert!(idx < 3 && arr[idx] == target),
5790+
Err(idx) => assert!(idx <= 3),
5791+
}
5792+
}
5793+
5794+
#[kani::proof]
5795+
#[kani::unwind(6)]
5796+
fn check_partition_dedup_by() {
5797+
let mut arr: [i32; SLICE_LEN] = kani::any();
5798+
let (dedup, dups) = arr.partition_dedup_by(|a, b| *a == *b);
5799+
assert_eq!(dedup.len() + dups.len(), SLICE_LEN);
5800+
}
5801+
5802+
#[kani::proof]
5803+
#[kani::unwind(5)]
5804+
fn check_rotate_left() {
5805+
let mut arr: [i32; 2] = kani::any();
5806+
let k: usize = kani::any();
5807+
kani::assume(k <= 2);
5808+
arr.rotate_left(k);
5809+
}
5810+
5811+
#[kani::proof]
5812+
#[kani::unwind(5)]
5813+
fn check_rotate_right() {
5814+
let mut arr: [i32; 2] = kani::any();
5815+
let k: usize = kani::any();
5816+
kani::assume(k <= 2);
5817+
arr.rotate_right(k);
5818+
}
5819+
5820+
#[kani::proof]
5821+
fn check_as_flattened() {
5822+
let arr: [[i32; 2]; 3] = kani::any();
5823+
let s: &[[i32; 2]] = &arr;
5824+
let flat: &[i32] = s.as_flattened();
5825+
assert_eq!(flat.len(), 6);
5826+
assert_eq!(flat[0], arr[0][0]);
5827+
assert_eq!(flat[5], arr[2][1]);
5828+
}
5829+
5830+
#[kani::proof]
5831+
fn check_as_flattened_mut() {
5832+
let mut arr: [[i32; 2]; 3] = kani::any();
5833+
let s: &mut [[i32; 2]] = &mut arr;
5834+
let flat: &mut [i32] = s.as_flattened_mut();
5835+
assert_eq!(flat.len(), 6);
5836+
flat[0] = 42;
5837+
assert_eq!(arr[0][0], 42);
5838+
}
5839+
5840+
#[kani::proof]
5841+
fn check_get_disjoint_mut() {
5842+
let mut arr: [i32; SLICE_LEN] = kani::any();
5843+
let a: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5844+
let b: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5845+
kani::assume(a != b);
5846+
let result = arr.get_disjoint_mut([a, b]);
5847+
assert!(result.is_ok());
5848+
let [ra, rb] = result.unwrap();
5849+
*ra = 1;
5850+
*rb = 2;
5851+
assert_eq!(arr[a], 1);
5852+
assert_eq!(arr[b], 2);
5853+
}
5854+
5855+
#[kani::proof]
5856+
fn check_get_disjoint_check_valid() {
5857+
let a: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5858+
let b: usize = kani::any_where(|&i: &usize| i < SLICE_LEN);
5859+
let indices = [a, b];
5860+
let result = get_disjoint_check_valid(&indices, SLICE_LEN);
5861+
if a == b {
5862+
assert!(result.is_err());
5863+
} else {
5864+
assert!(result.is_ok());
5865+
}
5866+
}
5867+
5868+
#[kani::proof]
5869+
fn check_as_simd() {
5870+
let arr: [f32; 4] = kani::any();
5871+
let s: &[f32] = &arr;
5872+
let (prefix, middle, suffix) = s.as_simd::<4>();
5873+
assert_eq!(prefix.len() + middle.len() * 4 + suffix.len(), 4);
5874+
}
5875+
5876+
#[kani::proof]
5877+
fn check_as_simd_mut() {
5878+
let mut arr: [f32; 4] = kani::any();
5879+
let s: &mut [f32] = &mut arr;
5880+
let (prefix, middle, suffix) = s.as_simd_mut::<4>();
5881+
assert_eq!(prefix.len() + middle.len() * 4 + suffix.len(), 4);
5882+
}
55115883
}

0 commit comments

Comments
 (0)