How can I allocate aligned Vec using safe code?

Hi,

I'd like to create a Vec<u8> aligned as u32, because I need to cast some slice later to u32 temporarily.

I searched and found solutions are using unsafe APIs (for example std::alloc::alloc ). Is there a way to use only safe code / API? (It's ok if the API has unsafe internally).

Thanks!

If possible, then the safest, most portable solution is to have the memory owned by a Vec<u32>, and cast slices to [u8] temporarily instead.

Of course, the [u8] slices can't be used to grow the vector, but that's important: Growing the vec would cause it to reallocate, and you don't have any control over that new allocation even if the initial one was suitably aligned.

Alternately, if you know which platform or allocator your code is using, you could rely on guarantees made by the specific allocator. For example, the system allocator on both Unix-like platforms and Windows will always return allocations that are aligned for all built-in types. So if you know you'll be using one of these allocators, I believe you can rely on Vec<u8> being at least 64-bit aligned (higher on some architectures).

3 Likes

Thanks. I think I'll try the route of allocating Vec<u32> and make sure I don't need to grow the vector. For casting, looks like there are crates providing safe API to do that.

Looks like I have to be able to extend / copy Vec<u8> into this Vec<u32>. I can use Vec::with_capacity() so that it will not reallocate, but still I have problem to get &mut Vec<u8> from the Vec<u32> in safe code.

And, I need to return the final result as Vec<u8> to the upper layer, which does not help.

I wouldn't suggest depending on system allocator alignment properties. It's possible that in future some operating systems will provide alignment aware allocators and Rust will move to those.

Your best bet is to have Vec<u32> from which you can get [u8] slices as mentioned above.

You'd need to initialize the Vec<u32>, either by using the resize method or by initializing it up-front with vec![0u32; size]. Then you can take slices of it, cast them to [u8], and copy into them with copy_from_slice.

Or if initialization proves too expensive, you can use raw pointers to write to the uninitialized part of the vector, and then set_len after it is initialized.

Is there any chance the upper layer could be changed to take something else, like a slice, or a generic type that implements AsRef<[u8]>? There's no way in fully-portable Rust to create a Vec<u8> from a 4-byte aligned allocation without copying.

You could write your own vec-like structure, or make a Vec<BigAlign>, but you can't make std's Vec<u8> use a different alignment. Contract between Vec and the allocator is that the alignment will be default for the type, and won't change.