Skip to content

Tracking issue for const <*const T>::is_null #74939

Closed

Description

@oli-obk

This is tracking #[feature(const_ptr_is_null)].

impl<T: ?Sized> *const T {
    pub const unsafe fn as_ref<'a>(self) -> Option<&'a T>;
    pub const fn is_null(&self) -> bool;
}

impl<T: ?Sized> *mut T {
    pub const unsafe fn as_mut<'a>(self) -> Option<&'a mut T>;
    pub const unsafe fn as_ref<'a>(self) -> Option<&'a T>;
    pub const fn is_null(&self) -> bool;
}

Comparing pointers in const eval is dangerous business.

But checking whether a pointer is the null pointer is actually completely fine, as Rust does not support items being placed at the null address. Any otherwise created null pointers are supposed to return true for is_null anyway, so that's ok. Thus, we implement is_null as ptr.guaranteed_eq(ptr::null()), which returns true if it's guaranteed that ptr is null, and there are no cases where it will return false where it may be null, but we don't know.

Activity

  1. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 30, 2020
  2. RalfJung commented on Aug 7, 2020

    @RalfJung
    Member

    and there are no cases where it will return false where it may be null, but we don't know.

    That's not entirely correct. It will at some point be possible to create out-of-bounds raw pointers in const-eval (it might be possible already with enough hacks, I am not sure). Once that is possible, a pointer could be offset enough such that it is NULL at run-time but still non-NULL when checked during CTFE -- we cannot know if out-of-bounds pointers are NULL as that depends on their concrete base address.

  3. oli-obk commented on Aug 10, 2020

    @oli-obk
    ContributorAuthor

    So, some examples that we ran reliably check:

    • std::ptr::null::<T>().is_null() will always be true
    • NonZeroUsize::new(x).unwrap().is_null() will always be false
    • `(&x as *const T).is_null() will always be false
    • ((&x as *const T as usize - &x as *const T as usize) as *const T).is_null() will always be true (if you get it or an equivalent to compile)

    The problematic case (&x as *const T).wrapping_offset(496).is_null() will be false, but at runtime could be true. We could set it up so it would be true instead, but then is_null() can return true when at runtime it would return false.

    Another alternative is to panic if no exact solution is known (this can be done in a way that it compiles away to nothing at runtime)

    Basically the options are:

    • use ptr.guaranteed_eq(std::ptr::null()), but then you get false for out of bounds pointers that at runtime are null
    • use !ptr.guaranteed_ne(std::ptr::null()), but then you get true for all out of bounds pointers, even the ones that are not null at runtime.
    • use both variants and assert that they return the same thing.
  4. josephlr commented on Sep 13, 2020

    @josephlr
    Contributor
    • use both variants and assert that they return the same thing.

    As a user, this seems the most natural to me.

    • Integer pointer that's zero => return true
    • Integer pointer that's non-zero => return false
    • Real pointer that's in-bounds => return false
    • Real pointer that's out-of-bounds => panic, could be either true/false at runtime.

    In general, panicking when doing something fundamentally non-const a cosnt fn seems fine.

  5. kupiakos commented on Mar 21, 2023

    @kupiakos
    Contributor

    Is there anything blocking stabilization of this? This also blocks NonNull::new from stabilization.

  6. RalfJung commented on Mar 22, 2023

    @RalfJung
    Member
  7. RalfJung commented on Sep 8, 2024

    @RalfJung
    Member

    Given in particular the use of is_null in NonNull::new/ptr::as_ref, I think the only possible interpretation it can have is "might be null": if we allow NonNull::new(ptr.wrapping_sub(0x120000)).unwrap() and later it turns out that pointer is at address 0x120000, we have a problem. Therefore, ptr.wrapping_sub(0x120000).is_null must be true.

    Or of course we could panic and thus abort const-eval. We'll never panic at runtime so this may be acceptable.

    @rust-lang/wg-const-eval any opinions on this?

  8. added 3 commits that reference this issue on Sep 9, 2024
  9. added a commit that references this issue on Sep 9, 2024
  10. added a commit that references this issue on Sep 10, 2024
  11. 52 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-langRelevant to the language teamT-libs-api[DEPRECATED; DO NOT USE]disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions