Auto merge of #143877 - xizheyin:143813, r=scottmcm,saethlin
`std::vec`: Add UB check for `set_len`, `from_raw_parts_in`, and etc. Closes rust-lang/rust#143813 I noticed that `from_parts_in` do the similar things like `from_raw_parts_in`, so I add the UB check in the last commit. If it is not appropriate, I will remove it. And I fix a typo in the first commit. r? `@scottmcm`
This commit is contained in:
commit
3014e79f9c
5 changed files with 73 additions and 3 deletions
|
|
@ -155,6 +155,7 @@
|
|||
#![feature(try_trait_v2)]
|
||||
#![feature(try_with_capacity)]
|
||||
#![feature(tuple_trait)]
|
||||
#![feature(ub_checks)]
|
||||
#![feature(unicode_internals)]
|
||||
#![feature(unsize)]
|
||||
#![feature(unwrap_infallible)]
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
|||
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::slice::{self, SliceIndex};
|
||||
use core::{fmt, intrinsics};
|
||||
use core::{fmt, intrinsics, ub_checks};
|
||||
|
||||
#[stable(feature = "extract_if", since = "1.87.0")]
|
||||
pub use self::extract_if::ExtractIf;
|
||||
|
|
@ -1058,6 +1058,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[inline]
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
|
||||
ub_checks::assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
"Vec::from_raw_parts_in requires that length <= capacity",
|
||||
(length: usize = length, capacity: usize = capacity) => length <= capacity
|
||||
);
|
||||
unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
|
||||
}
|
||||
|
||||
|
|
@ -1174,6 +1179,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[unstable(feature = "allocator_api", reason = "new API", issue = "32838")]
|
||||
// #[unstable(feature = "box_vec_non_null", issue = "130364")]
|
||||
pub unsafe fn from_parts_in(ptr: NonNull<T>, length: usize, capacity: usize, alloc: A) -> Self {
|
||||
ub_checks::assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
"Vec::from_parts_in requires that length <= capacity",
|
||||
(length: usize = length, capacity: usize = capacity) => length <= capacity
|
||||
);
|
||||
unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
|
||||
}
|
||||
|
||||
|
|
@ -1950,7 +1960,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn set_len(&mut self, new_len: usize) {
|
||||
debug_assert!(new_len <= self.capacity());
|
||||
ub_checks::assert_unsafe_precondition!(
|
||||
check_library_ub,
|
||||
"Vec::set_len requires that new_len <= capacity()",
|
||||
(new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity
|
||||
);
|
||||
|
||||
self.len = new_len;
|
||||
}
|
||||
|
|
@ -3695,7 +3709,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
/// This is optimal if:
|
||||
///
|
||||
/// * The tail (elements in the vector after `range`) is empty,
|
||||
/// * or `replace_with` yields fewer or equal elements than `range`’s length
|
||||
/// * or `replace_with` yields fewer or equal elements than `range`'s length
|
||||
/// * or the lower bound of its `size_hint()` is exact.
|
||||
///
|
||||
/// Otherwise, a temporary vector is allocated and the tail is moved twice.
|
||||
|
|
|
|||
15
tests/ui/precondition-checks/vec-from-parts.rs
Normal file
15
tests/ui/precondition-checks/vec-from-parts.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -Cdebug-assertions=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity
|
||||
#![feature(allocator_api)]
|
||||
|
||||
use std::ptr::NonNull;
|
||||
|
||||
fn main() {
|
||||
let ptr: NonNull<i32> = std::ptr::NonNull::dangling();
|
||||
// Test Vec::from_parts_in with length > capacity
|
||||
unsafe {
|
||||
let alloc = std::alloc::Global;
|
||||
let _vec = Vec::from_parts_in(ptr, 10, 5, alloc);
|
||||
}
|
||||
}
|
||||
29
tests/ui/precondition-checks/vec-from-raw-parts.rs
Normal file
29
tests/ui/precondition-checks/vec-from-raw-parts.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -Cdebug-assertions=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity
|
||||
//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts
|
||||
|
||||
#![feature(allocator_api)]
|
||||
|
||||
fn main() {
|
||||
let ptr = std::ptr::null_mut::<u8>();
|
||||
// Test Vec::from_raw_parts with length > capacity
|
||||
unsafe {
|
||||
#[cfg(vec_from_raw_parts)]
|
||||
let _vec = Vec::from_raw_parts(ptr, 10, 5);
|
||||
}
|
||||
|
||||
// Test Vec::from_raw_parts_in with length > capacity
|
||||
unsafe {
|
||||
let alloc = std::alloc::Global;
|
||||
#[cfg(vec_from_raw_parts_in)]
|
||||
let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc);
|
||||
}
|
||||
|
||||
// Test String::from_raw_parts with length > capacity
|
||||
// Because it calls Vec::from_raw_parts, it should also fail
|
||||
unsafe {
|
||||
#[cfg(string_from_raw_parts)]
|
||||
let _vec = String::from_raw_parts(ptr, 10, 5);
|
||||
}
|
||||
}
|
||||
11
tests/ui/precondition-checks/vec-set-len.rs
Normal file
11
tests/ui/precondition-checks/vec-set-len.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//@ run-fail
|
||||
//@ compile-flags: -Cdebug-assertions=yes
|
||||
//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()
|
||||
|
||||
fn main() {
|
||||
let mut vec: Vec<i32> = Vec::with_capacity(5);
|
||||
// Test set_len with length > capacity
|
||||
unsafe {
|
||||
vec.set_len(10);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue