Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion library/kani_core/src/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ macro_rules! kani_mem {

/// Compute the size of the val pointed to if it is safe to do so.
///
/// Return `None` if an overflow would occur, or if alignment is not power of two.
/// Returns `None` if:
/// - An overflow occurs during the size computation.
/// - The pointer’s alignment is not a power of two.
/// - The computed size exceeds `isize::MAX` (the maximum safe Rust allocation size).
/// TODO: Optimize this if T is sized.
#[kanitool::fn_marker = "CheckedSizeOfIntrinsic"]
pub fn checked_size_of_raw<T: ?Sized>(ptr: *const T) -> Option<usize> {
Expand Down Expand Up @@ -166,6 +169,14 @@ macro_rules! kani_mem {
/// Checks that `ptr` points to an allocation that can hold data of size calculated from `T`.
///
/// This will panic if `ptr` points to an invalid `non_null`
/// Returns `false` if:
/// - The computed size overflows.
/// - The computed size exceeds `isize::MAX`.
/// - The pointer is null (except for zero-sized types).
/// - The pointer references unallocated memory.
Copy link

Choose a reason for hiding this comment

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

This should probably also clarify that it doesn't apply for zero-sized types. Per the std::ptr docs:

For memory accesses of size zero, every pointer is valid, including the null pointer.

Copy link
Contributor

Choose a reason for hiding this comment

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

I created #3974 to address this

///
/// This function aligns with Rust's memory safety requirements, which restrict valid allocations
/// to sizes no larger than `isize::MAX`.
fn is_inbounds<T: ?Sized>(ptr: *const T) -> bool {
// If size overflows, then pointer cannot be inbounds.
let Some(sz) = checked_size_of_raw(ptr) else { return false };
Expand Down
1 change: 1 addition & 0 deletions tests/expected/MemPredicates/ptr_size_validity.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Complete - 1 successfully verified harnesses, 0 failures, 1 total.
21 changes: 21 additions & 0 deletions tests/expected/MemPredicates/ptr_size_validity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright Kani Contributors
// SPDX-License-Identifier: Apache-2.0 OR MIT
// kani-flags: -Z mem-predicates
#![feature(ptr_metadata)]

extern crate kani;

mod size {
use super::*;

#[kani::proof]
fn verify_checked_size_of_raw_exceeds_isize_max() {
let len_exceeding_isize_max = (isize::MAX as usize) + 1;
let data_ptr: *const [u8] =
core::ptr::from_raw_parts(core::ptr::null::<u8>(), len_exceeding_isize_max);

let size = kani::mem::checked_size_of_raw(data_ptr);

assert!(size.is_none());
}
}
Loading