Skip to content

Prohibit Vec::set_len beyond capacity #14836

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

Closed
wants to merge 1 commit into from

Conversation

stepancheg
Copy link
Contributor

Vec::set_len operation is useful for I/O (reading into uninitialized
memory), however it is too easy to corrupt memory by setting length
larger than capacity.

On the other hand, setting length larger than capacity is almost useless
in practice.

So set_len should not allow to set length larger than capacity.

`Vec::set_len` operation is useful for I/O (reading into uninitialized
memory), however it is too easy to corrupt memory by setting length
larger than capacity.

On the other hand, setting length larger than capacity is almost useless
in practice.

So `set_len` should not allow to set length larger than capacity.
@thestinger
Copy link
Contributor

It's not really much safer with this check and it's going to add a lot of overhead to some of the algorithms where this is performed in a loop. It's memory unsafe just to extend the length past the initialized data because of the semantics of undefined data in LLVM.

@stepancheg
Copy link
Contributor Author

Range check in set_len makes this code safe:

let mut buf: Vec<u8> = Vec::with_capacity(10000);
buf.set_len(100000); // <-- hard to spot problem is here
file.read_into(buf.as_mut_slice());
return buf;

@alexcrichton
Copy link
Member

Note that this does not change from_raw_parts, which would have the two methods be inconsistent.

@thestinger
Copy link
Contributor

@stepancheg: That example would be memory safe. It would often leave uninitialized data at the end of the vector included in the length. In reasonable code the length would be in a constant rather than a repeated magic number, although here it would really be set based on the number of bytes read.

If there's going to be a check in set_len, then we need an unchecked version too. The overhead of unnecessary branches and failure needs to be avoided in performance critical code. Any function calling set_len is now impure due to unwinding.

@stepancheg
Copy link
Contributor Author

@alexcrichton I'm unsure about from_raw_parts, because if assertion in from_raw_parts fails, memory is leaked.

@lilyball
Copy link
Contributor

set_len() is already an unsafe function that exposes uninitialized memory. I don't think adding an assertion makes it really any safer, and instead just serves as a way to slow down existing code that uses this method.

@alexcrichton
Copy link
Member

Closing due to inactivity. It sounds like this may not be desired, but feel free to reopen if you'd like to.

bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants