Description
As discussed here, methods like Vec::with_capacity
are guaranteed to create a container with at least the specified capacity, but are allowed to allocate more.
The easiest way to see this is with zero-sized types, since no allocation is necessary and capacity is always usize::MAX
(I assume).
However, the documentation states "Constructs a new, empty Vec<T>
with the specified capacity. The vector will be able to hold exactly capacity elements without reallocating." This is wrong, especially so with the use of the word "exactly". I've picked on Vec::with_capacity
here, but all of the other standard library with_capacity
and with_capacity_in
methods I've checked have the same issue.
Obviously the case of zero-sized types is a trivial example, but this is a safety issue if you're breaking containers into raw parts (e.g. for FFI) and then reconstructing them. For example the following is not sound, but the documentation says it is:
const CAPACITY: usize = 123;
let mut cstr = Vec::<u8>::with_capacity(CAPACITY);
let ptr = cstr.as_mut_ptr();
let mut length = 0;
std::mem::forget(cstr);
let returned_string = unsafe {
ffi_that_fills_the_string(CAPACITY, &mut length, ptr);
Vec::from_raw_parts(ptr, length, CAPACITY);
}
let returned_string = String::from_utf8(returned_string)?;
Since the allocator is allowed to allocate more than CAPACITY
, making the call to from_raw_parts
unsound.
The documentation for reserve
and reserve_exact
on the other hand are accurate (though I'm not sure why reserve_exact
exists, or certainly why it has that name, if it can't guarantee exact allocation).