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

Unclear is offsetting one element past array length is allowed #138969

Open
Rosdf opened this issue Mar 26, 2025 · 4 comments · Fixed by #138976
Open

Unclear is offsetting one element past array length is allowed #138969

Rosdf opened this issue Mar 26, 2025 · 4 comments · Fixed by #138976
Assignees
Labels
A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools A-raw-pointers Area: raw pointers, MaybeUninit, NonNull needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. T-opsem Relevant to the opsem team

Comments

@Rosdf
Copy link

Rosdf commented Mar 26, 2025

Location

https://doc.rust-lang.org/std/primitive.pointer.html#method.offset

Summary

Offset doc states that

If the computed offset is non-zero, then self must be derived from a pointer to some allocated object, and the entire memory range between self and the result must be in bounds of that allocated object.

allocated object doc states that

For all addresses a in addresses, a is in the range base .. (base + size) (note that this requires a < base + size, not a <= base + size)

so as i understand offsetting pointer to the head of an array one past it's length should not be allowed, but in practice it is allowed

fn main() {
    static A: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
    static mut B: *const u8 = unsafe {A.as_ptr().offset(8)};
}

this code compiles just fine, but this one produces an error

fn main() {
    static A: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
    static mut B: *const u8 = unsafe {A.as_ptr().offset(9)};
}
error[E0080]: could not evaluate static initializer
   --> /home/daria/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:455:18
    |
455 |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 9 bytes of memory, but got alloc1 which is only 8 bytes from the end of the allocation
    |
note: inside `std::ptr::const_ptr::<impl *const u8>::offset`
   --> /home/daria/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:455:18
    |
455 |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `B`
   --> src/main.rs:3:39
    |
3   |     static mut B: *const u8 = unsafe {A.as_ptr().offset(9)};
    |                                       ^^^^^^^^^^^^^^^^^^^^
@Rosdf Rosdf added the A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools label Mar 26, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Mar 26, 2025
@xizheyin
Copy link
Contributor

As far as I know, while the documentation states that pointers must be within the bounds of the allocated object (a < base + size), there is indeed a special case: "one-past-the-end" pointers are explicitly allowed. "One-past-the-end" pointers are crucial for iteration, allowing representation of the end of a valid range. It enables more natural range checking and pointer arithmetic implementations. Maybe the documentation should be improved.

@xizheyin
Copy link
Contributor

@rustbot claim

@moxian
Copy link
Contributor

moxian commented Mar 27, 2025

@rustbot label: +T-opsem +T-libs-api +A-raw-pointers

@rustbot rustbot added A-raw-pointers Area: raw pointers, MaybeUninit, NonNull T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. T-opsem Relevant to the opsem team labels Mar 27, 2025
@RalfJung
Copy link
Member

so as i understand offsetting pointer to the head of an array one past it's length should not be allowed,

No, you misunderstood. The "offset" docs are very explicit about this:
"the entire memory range between self and the result must be in bounds of that allocated object."

If you do A.as_ptr().offset(8), the range between the old and new pointer is the range covering the indices 0..8. That entire range is within the bounds of the array.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 28, 2025
Explain one-past-the-end pointer in std library

Closing rust-lang#138969

r? libs
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Mar 29, 2025
Rollup merge of rust-lang#138976 - xizheyin:issue-138969, r=RalfJung

Explain one-past-the-end pointer in std library

Closing rust-lang#138969

r? libs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools A-raw-pointers Area: raw pointers, MaybeUninit, NonNull needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. T-opsem Relevant to the opsem team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants