Skip to content

size_of_val_raw doesn't assume that [u8] has size at most isize::MAX #159754

Open

Description

@theemathas

I tried this code:

#![feature(layout_for_ptr)]
use std::mem::size_of_val_raw;

#[unsafe(no_mangle)]
pub fn a(x: *const [u8]) -> bool {
    unsafe { size_of_val_raw(x) <= isize::MAX.cast_unsigned() }
}

#[unsafe(no_mangle)]
pub fn b(x: *const [u16]) -> bool {
    unsafe { size_of_val_raw(x) <= isize::MAX.cast_unsigned() }
}

I expected both functions to optimize to returning true, since the documentation for size_of_val_raw states that, for the operation to not be UB, the size of the slice must be at most isize::MAX.

Instead, only the b function optimizes to returning true.

Godbolt link

a:
        test    rsi, rsi
        setns   al
        ret

b:
        mov     al, 1
        ret

Meta

Reproducible on godbolt with version info:

rustc 1.99.0-nightly (0e29c21d9 2026-07-21)
binary: rustc
commit-hash: 0e29c21d93abc9bdc330182be1fbd33cfd5fee68
commit-date: 2026-07-21
host: x86_64-unknown-linux-gnu
release: 1.99.0-nightly
LLVM version: 22.1.8
Internal compiler ID: nightly

Activity

  1. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    A-layoutArea: Memory layout of types
    A-raw-pointersArea: raw pointers, MaybeUninit, NonNull
    C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing such
    on Jul 23, 2026
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Jul 23, 2026
  3. hanna-kruppe commented on Jul 23, 2026

    @hanna-kruppe
    Contributor

    This is probably because rustc encodes the size-in-bytes restriction by making the len * size_of::<T>() multiply nuw nsw and that doesn’t imply anything when size_of::<T>() == 1.

  4. hanna-kruppe commented on Jul 23, 2026

    @hanna-kruppe
    Contributor

    I guess we could fix this by special casing 1-byte-sized element types to emit assume(len <= isize::MAX). The same special case could avoid emitting the unnecessary multiply to sweeten the deal. But I’m not sure it’s worth it (assumes have downsides/costs, so it’s better to have evidence of real world impact before adding them).

  5. asquared31415 commented on Jul 23, 2026

    @asquared31415
    Contributor

    @rustbot claim

  6. hanna-kruppe commented on Jul 26, 2026

    @hanna-kruppe
    Contributor

    @theemathas Is this minimized from some less trivial code where lack of range information caused missed optimizations? If yes, could you share it?

  7. theemathas commented on Jul 26, 2026

    @theemathas
    ContributorAuthor

    I was just playing around with some code after reading the safety requirements of size_of_val_raw 😅

  8. asquared31415 commented on Jul 27, 2026

    @asquared31415
    Contributor

    Update from #159921: we're not seeing any significant optimization improvements when providing the necessary information to LLVM via assume in the case of *const [u8] (and similar). LLVM does become able to optimize the example cases in the original issue report, but we overall see some compile time regressions, presumably because of the additional IR for LLVM to manipulate. It may be possible to mitigate the regressions by introducing a second intrinsic for size_of_val_raw to call specifically, but it would likely need to come with more convincing optimization improvements to justify the complexity.

    @rustbot release-assignment

  9. scottmcm commented on Jul 28, 2026

    @scottmcm
    Member

    This is one of those places where I wish we has a mem::Size to return, like we have mem::Alignment. Then the assertion -- and range metadata -- could be carried by that type in the return value.

    For LLVM, though, the other thing that would be nice is if we could have range assume operand bundles, which would be less impactful than needing the icmp. Last I checked those don't work, though.

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-layoutArea: Memory layout of typesA-raw-pointersArea: raw pointers, MaybeUninit, NonNullC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamneeds-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions