Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Support same_allocation for API under implementation with ?Size type #3665

Closed
danielhumanmod opened this issue Oct 31, 2024 · 1 comment · Fixed by #3684
Labels
[C] Feature / Enhancement A new feature request or enhancement to an existing feature.

Comments

@danielhumanmod
Copy link

Hi team,
I am trying to use the same_allocation API to verify whether two pointers refer to the same object allocation. However, for the API under the implementation impl<T: ?Sized> NonNull<T>, it seems this API is not permitted. Below is the relevant code snippet:

// Function Contracts (under the implementation of impl<T: ?Sized> NonNull<T>) 
    #[must_use]
    #[inline(always)]
    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
    #[rustc_allow_const_fn_unstable(set_ptr_value)]
    #[stable(feature = "non_null_convenience", since = "1.80.0")]
    #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")]
    #[requires(kani::mem::same_allocation(self.as_ptr(), self.as_ptr().wrapping_offset(count)))]
    #[ensures(
        |result: &NonNull<T>|
        (result.as_ptr() as *const () as usize) == ((self.as_ptr() as *const () as usize) + count)
    )]
    pub const unsafe fn byte_add(self, count: usize) -> Self {
        // SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same
        // safety contract.
        // Additionally safety contract of `add` guarantees that the resulting pointer is pointing
        // to an allocation, there can't be an allocation at null, thus it's safe to construct
        // `NonNull`.
        unsafe { NonNull { pointer: self.pointer.byte_add(count) } }
    }

// Proof Harness
    #[kani::proof_for_contract(NonNull::byte_add)]
    pub fn non_null_byte_add_proof() {
        const ARR_SIZE: usize = 100000;
        let arr: [i32; ARR_SIZE] = kani::any();
        let offset = kani::any_where(|x| *x <= ARR_SIZE);
        let raw_ptr: *mut i32 = arr.as_ptr() as *mut i32;
        let ptr = unsafe { NonNull::new(raw_ptr.add(offset)).unwrap() };
        let count: usize = kani::any();

        kani::assume(count < usize::MAX);
        kani::assume(count.checked_mul(mem::size_of::<i32>()).is_some());
        kani::assume(count * mem::size_of::<i32>() <= (isize::MAX as usize));
        // kani::assume(count < ARR_SIZE - offset);

        unsafe {
            let result = ptr.byte_add(count);
        }
    }

This issue is originally discussed in model-checking/verify-rust-std#141

@danielhumanmod danielhumanmod added the [C] Feature / Enhancement A new feature request or enhancement to an existing feature. label Oct 31, 2024
@celinval
Copy link
Contributor

celinval commented Nov 1, 2024

Hi @danielhumanmod, thanks for creating this issue. We should definitely extend the API to accept non-sized pointers. In the meantime, you should be able to retrieve the thin pointer and use that instead. You can use let (thin, _) = pointer::to_raw_parts().

github-merge-queue bot pushed a commit that referenced this issue Nov 6, 2024
For that, change the function to cast the given pointer to a thin
pointer of type `*const ()`, and use that instead.

Resolves #3665

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[C] Feature / Enhancement A new feature request or enhancement to an existing feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants