Skip to content

Commit 3014e79

Browse files
committed
Auto merge of #143877 - xizheyin:143813, r=scottmcm,saethlin
`std::vec`: Add UB check for `set_len`, `from_raw_parts_in`, and etc. Closes #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`
2 parents e27f16a + a74a284 commit 3014e79

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
#![feature(try_trait_v2)]
156156
#![feature(try_with_capacity)]
157157
#![feature(tuple_trait)]
158+
#![feature(ub_checks)]
158159
#![feature(unicode_internals)]
159160
#![feature(unsize)]
160161
#![feature(unwrap_infallible)]

library/alloc/src/vec/mod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
6464
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
6565
use core::ptr::{self, NonNull};
6666
use core::slice::{self, SliceIndex};
67-
use core::{fmt, intrinsics};
67+
use core::{fmt, intrinsics, ub_checks};
6868

6969
#[stable(feature = "extract_if", since = "1.87.0")]
7070
pub use self::extract_if::ExtractIf;
@@ -1058,6 +1058,11 @@ impl<T, A: Allocator> Vec<T, A> {
10581058
#[inline]
10591059
#[unstable(feature = "allocator_api", issue = "32838")]
10601060
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
1061+
ub_checks::assert_unsafe_precondition!(
1062+
check_library_ub,
1063+
"Vec::from_raw_parts_in requires that length <= capacity",
1064+
(length: usize = length, capacity: usize = capacity) => length <= capacity
1065+
);
10611066
unsafe { Vec { buf: RawVec::from_raw_parts_in(ptr, capacity, alloc), len: length } }
10621067
}
10631068

@@ -1174,6 +1179,11 @@ impl<T, A: Allocator> Vec<T, A> {
11741179
#[unstable(feature = "allocator_api", reason = "new API", issue = "32838")]
11751180
// #[unstable(feature = "box_vec_non_null", issue = "130364")]
11761181
pub unsafe fn from_parts_in(ptr: NonNull<T>, length: usize, capacity: usize, alloc: A) -> Self {
1182+
ub_checks::assert_unsafe_precondition!(
1183+
check_library_ub,
1184+
"Vec::from_parts_in requires that length <= capacity",
1185+
(length: usize = length, capacity: usize = capacity) => length <= capacity
1186+
);
11771187
unsafe { Vec { buf: RawVec::from_nonnull_in(ptr, capacity, alloc), len: length } }
11781188
}
11791189

@@ -1950,7 +1960,11 @@ impl<T, A: Allocator> Vec<T, A> {
19501960
#[inline]
19511961
#[stable(feature = "rust1", since = "1.0.0")]
19521962
pub unsafe fn set_len(&mut self, new_len: usize) {
1953-
debug_assert!(new_len <= self.capacity());
1963+
ub_checks::assert_unsafe_precondition!(
1964+
check_library_ub,
1965+
"Vec::set_len requires that new_len <= capacity()",
1966+
(new_len: usize = new_len, capacity: usize = self.capacity()) => new_len <= capacity
1967+
);
19541968

19551969
self.len = new_len;
19561970
}
@@ -3695,7 +3709,7 @@ impl<T, A: Allocator> Vec<T, A> {
36953709
/// This is optimal if:
36963710
///
36973711
/// * The tail (elements in the vector after `range`) is empty,
3698-
/// * or `replace_with` yields fewer or equal elements than `range`s length
3712+
/// * or `replace_with` yields fewer or equal elements than `range`'s length
36993713
/// * or the lower bound of its `size_hint()` is exact.
37003714
///
37013715
/// Otherwise, a temporary vector is allocated and the tail is moved twice.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ run-fail
2+
//@ compile-flags: -Cdebug-assertions=yes
3+
//@ error-pattern: unsafe precondition(s) violated: Vec::from_parts_in requires that length <= capacity
4+
#![feature(allocator_api)]
5+
6+
use std::ptr::NonNull;
7+
8+
fn main() {
9+
let ptr: NonNull<i32> = std::ptr::NonNull::dangling();
10+
// Test Vec::from_parts_in with length > capacity
11+
unsafe {
12+
let alloc = std::alloc::Global;
13+
let _vec = Vec::from_parts_in(ptr, 10, 5, alloc);
14+
}
15+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ run-fail
2+
//@ compile-flags: -Cdebug-assertions=yes
3+
//@ error-pattern: unsafe precondition(s) violated: Vec::from_raw_parts_in requires that length <= capacity
4+
//@ revisions: vec_from_raw_parts vec_from_raw_parts_in string_from_raw_parts
5+
6+
#![feature(allocator_api)]
7+
8+
fn main() {
9+
let ptr = std::ptr::null_mut::<u8>();
10+
// Test Vec::from_raw_parts with length > capacity
11+
unsafe {
12+
#[cfg(vec_from_raw_parts)]
13+
let _vec = Vec::from_raw_parts(ptr, 10, 5);
14+
}
15+
16+
// Test Vec::from_raw_parts_in with length > capacity
17+
unsafe {
18+
let alloc = std::alloc::Global;
19+
#[cfg(vec_from_raw_parts_in)]
20+
let _vec = Vec::from_raw_parts_in(ptr, 10, 5, alloc);
21+
}
22+
23+
// Test String::from_raw_parts with length > capacity
24+
// Because it calls Vec::from_raw_parts, it should also fail
25+
unsafe {
26+
#[cfg(string_from_raw_parts)]
27+
let _vec = String::from_raw_parts(ptr, 10, 5);
28+
}
29+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-fail
2+
//@ compile-flags: -Cdebug-assertions=yes
3+
//@ error-pattern: unsafe precondition(s) violated: Vec::set_len requires that new_len <= capacity()
4+
5+
fn main() {
6+
let mut vec: Vec<i32> = Vec::with_capacity(5);
7+
// Test set_len with length > capacity
8+
unsafe {
9+
vec.set_len(10);
10+
}
11+
}

0 commit comments

Comments
 (0)