Why does calling Vec :: resize before calling Vec :: set_len cause Vec to have data?

I have a problem that I don't understand:

fn cipher_with(key: &[u8], data: &[u8]) -> Vec<u8> {
    let data_len = 16;

    let mut data = data.to_vec();
    data.resize(data_len, 2);

    let mut output = Vec::<u8>::with_capacity(data_len);
    unsafe { output.set_len(data_len) }

    output
}

fn main() {
    let key = "blabla".as_bytes();
    let data = "lorem ipsum.".as_bytes();
    println!("{:?}", cipher_with(&key, &data));
}

      

Prints:

[108, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 46, 0, 0, 0, 0]

But how is it done? I have never given this meaning output

.

+3


source to share


2 answers


To add some detail to Peter's answer , check out this annotated version:

fn cipher_with(key: &[u8], data: &[u8]) -> Vec<u8> {
    let data_len = 16;

    let mut data = data.to_vec();
    println!("{:?}", data.as_ptr());
    data.resize(data_len, 2);
    println!("{:?}", data.as_ptr());

    let mut output = Vec::<u8>::with_capacity(data_len);
    println!("{:?}", output.as_ptr());
    unsafe { output.set_len(data_len) }

    output
}

      

0x7fa6dba27000
0x7fa6dba1e0c0
0x7fa6dba27000

      



When the first vector is created, it has a length of 12. When it is resized to 16, a new selection will be created and the data copied. This is probably due to the implementation of the allocator, which normally allocates chunks. 16 would be a reasonable bucket size.

When the second vector is created, the allocator passes the same pointer as the first vector. Since nothing else has changed this memory during this time, it still contains any data in the data

.

+5


source


You are using unsafe Rust, which can give you unpredictable results.

In this particular case, you are expanding the size Vec

into uninitialized memory. The values ​​already exist.

So let's take a look at some of the code:

let mut data = data.to_vec();

      

This copies the "lorem ipsum" data. on the heap as a vector.



data.resize(data_len, 2); // data_len = 16

      

This increases the capacity Vec

from 12 to 16 elements, which in this case are bytes. But in fact, based on what we can see, it looks like the implementation (or perhaps the optimizer) has decided that it is better to simply discard the first allocated memory range and copy the data into new memory.

let mut output = Vec::<u8>::with_capacity(data_len);
unsafe { output.set_len(data_len) }

      

This creates a new vector and doesn't give it a length. But you haven't initialized it, so the data will be as it was before.

It looks like it data.resize()

actually copied the value instead of just dropping the end of the vector. When it output

was allocated, it was allocated the same block of memory that was previously used, so it contains "lorem ipsum."

.

+3


source







All Articles