Change:
The safety clause on the function says that: newlen must be less than or equal to capacity(). The elements at must be initialized. However, the code example for violates the second rule The is called before the values are initialized with the copy. This could be fixed by either making the safety clause for lines around in the example.
Eventually Rust will need pre-conditions and post-conditions to verify statically and automatically that (most) invariants of unsafe functions hold :-)
Isn't the point of unsafe code that you yourself uphold the invariants?
yeah, afaict the safety conditions of currently do not guarantee that doesn't look at any elements, so this would be an allowed implementation of afaict. We "obviously" do not do this, but I guess cc on what's the right wording here.
Currently yes, but surely that isn't a requirement. Having some mechanical ways to avoid some bugs in unsafe{} sections will be very good, even if it doesn't cover everything. There are people working on the formalization of (unsafe) Rust semantics that have this purposes too. And in some cases it's not that hard, is well within the capabilities of other research languages, like here: The second SAFETY note says: // SAFETY: A 's pointer is always aligned properly, and // the alignment the array needs is the same as the items. // We checked earlier that we have sufficient items. // The items will not double-drop as the // tells the not to also drop them. Zig language gives pointers a static alignment annotation in the type system. And probably the annotations of a language like Why3 are enough for the other part.
I think this discussion is irrelevant to the issue. What we should be discussing is what to do; change setlen safety guarantees, because "We 'obviously' do not do this", or change the example. I'm leaning towards making the safety guarantees for setlen less strict, because that would allow for more flexible usage of the function.
However, changing the safety on the . In my experience rust doesn't like invariants to be broken even for just short periods of time inside unsafe code, so just fixing the example may be a better choice that fits better with how rust works.
The real heart of things is that code within the module is allowed to break the safety invariant as long as they don't break the validity invariant. As long as things are all put back together properly by the end of the function.
A code example is not within the module
Ah my mistake! I thought this was a vector construction method on the vec type. If this is anywhere else at all then the two lines need to be swapped so that comes after the initialization.
Exactly. Give that already makes plenty of , I think it would be reasonable to say that itself is safe no matter which length you set, but before you use the vector again (i.e., before you call any vector operation, including ), you must ensure that the given invariants hold. However, to make the example code correct, we'd additionally have to say that is always safe to call, despite the "do not call any other operation" in . All of this is a roundabout way to say that can violate the safety invariant (or "library invariant") of the type, and that is okay to call even when the safety invariant is currently violated.
Note that we currently have a debug assert in setlen for , so setting the len to something greater than the capacity can currently panic which probably can cause unsoundness as it would be unexpected. If we want to change the safety guarantees here we probably should remove that debug_assert (even if they aren't actually part of the std used with rustup afaik)
good point. Or we could say that a length larger than the capacity is insta-UB (library UB).
If also be safe in those situations?
Not sure if it's worth the complexity to have all these edge cases when ` are simpler alternatives. Even if it's fine for Vec, what about other collections? Should those also have edge cases? I think it would get messy very fast.
Yes, probably. is special in that it already makes a bunch of .
Is needing to move the later painful enough in practice to be worth the more complicated soundness requirements on it? Any length increase would need to be after the population for panic-safety in general anyway (of course a memmove as here is fine, but in other places that's not always obvious).
We should just move the line in the example. Complicating the method's rules would be a bad time.
See "Code 15" this paper for another example of "calling before populating is bad": -- and then "calling after taking is bad" in "Code 20".
No strong opinion from my side, I just didn't want to unnecessarily exclude existing unsafe code that is using correctly (such as the example, in fact).

Discussion:
/// ``` /// use std::ptr; /// <ins> /// /// # Safety: /// /// * `ptr` must be correctly aligned for its type and non-zero. /// /// * `ptr` must be valid for reads of `elts` contiguous objects of type `T`. /// /// * Those elements must not be used after calling this function unless `T: Copy`. </ins> /// # #[allow(dead_code)] /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> { ///     let mut dst = Vec::with_capacity(elts); <del> ///     dst.set_len(elts); </del> <ins> /// ///     // SAFETY: Our precondition ensures the source is aligned and valid, ///     // and `Vec::with_capacity` ensures that we have usable space to write them. </ins> ///     ptr::copy(ptr, dst.as_mut_ptr(), elts); <ins> /// ///     // SAFETY: We created it with this much capacity earlier, ///     // and the previous `copy` has initialized these elements. ///     dst.set_len(elts); </ins> ///     dst /// } /// ```