Skip to content

Clarify safety invariants in Vec::from_raw_parts #139816

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

Open
SyxtonPrime opened this issue Apr 14, 2025 · 1 comment
Open

Clarify safety invariants in Vec::from_raw_parts #139816

SyxtonPrime opened this issue Apr 14, 2025 · 1 comment
Labels
A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@SyxtonPrime
Copy link

Location

https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts

Summary

Currently the documentation of Vec::from_raw_parts claims that both:

  • The size of T times the capacity (ie. the allocated size in bytes) needs to be the same size as the pointer was allocated with.
  • capacity needs to be the capacity that the pointer was allocated with.

This is somewhat confusing. The first condition arises from #95016 which explicitly removed the second condition in favor of the first. The second condition was then added back in in #99216 without any specific comment about it being necessary.

Together these conditions imply that T needs to have the same size and alignment as what ptr was allocated with. But the whole point of #95016 is that this isn't actually the case. (If this is actually the case, I think this could be reworded to be more clear)

Broadly what I am trying to understand is if the following 2 bits of code which convert between Vec<[T; N]> and Vec<T> are UB or not:

fn flatten<const N: usize>(vec: Vec<[T; N]>) -> Vec<T> {
   let mut v = mem::ManuallyDrop::new(v);
   
   let len = v.len() * N;
   let cap = v.capacity() * N;
   let p = v.as_mut_ptr() as *mut T;
   unsafe {
      Vec::from_raw_parts(ptr, new_len, new_cap)
   }
}

fn recombine<const N: usize>(vec: Vec<T>) -> Vec<[T; N]> {
   let mut v = mem::ManuallyDrop::new(v);
   
   assert_eq!(v.len() % N == 0);
   assert_eq!(v.capacity() % N == 0);
   
   let len = v.len() / N;
   let cap = v.capacity() / N;
   let p = v.as_mut_ptr() as *mut [T; N];
   unsafe {
      Vec::from_raw_parts(ptr, new_len, new_cap)
   }
}

As far as I can tell these should work (and seem to in the playground) but they rely on the second condition being overly strict and the first condition being the one which matters,

@SyxtonPrime SyxtonPrime added the A-docs Area: Documentation for any part of the project, including the compiler, standard library, and tools label Apr 14, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 14, 2025
@lolbinarycat
Copy link
Contributor

related: #119304

@lolbinarycat lolbinarycat added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Apr 14, 2025
@jieyouxu jieyouxu added T-libs Relevant to the library team, which will review and decide on the PR/issue. and removed T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 15, 2025
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 T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants