From 10866f46172e92a7949dca2e5a52b8c444a5b082 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 15:51:32 +0800 Subject: [PATCH 1/5] Fix typo in `std::vec` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c8341750f4d36..a4741f30fa5ad 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3695,7 +3695,7 @@ impl Vec { /// 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. From 1cab09ed9c582e7804bd0f9a6ead61129bb537d5 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:06:53 +0800 Subject: [PATCH 2/5] `std::vec`: Upgrade `debug_assert` to UB check in `set_len` Signed-off-by: xizheyin --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4290bb7a8a932..947df24d44f52 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -153,6 +153,7 @@ #![feature(try_trait_v2)] #![feature(try_with_capacity)] #![feature(tuple_trait)] +#![feature(ub_checks)] #![feature(unicode_internals)] #![feature(unsize)] #![feature(unwrap_infallible)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a4741f30fa5ad..da3d3596d1922 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -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; @@ -1950,7 +1950,11 @@ impl Vec { #[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; } From 090c177003272da7d2d3b04702f35261d3952b72 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:17:43 +0800 Subject: [PATCH 3/5] std::vec: Add UB check in `from_raw_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index da3d3596d1922..6d44681fb28b2 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1058,6 +1058,11 @@ impl Vec { #[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 } } } From 48caa5f8897263da935ebdc2bbec8a95b5d3d025 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 13 Jul 2025 16:18:56 +0800 Subject: [PATCH 4/5] std::vec: Add UB check in `from_parts_in` Signed-off-by: xizheyin --- library/alloc/src/vec/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6d44681fb28b2..50f8cc375bfe0 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1179,6 +1179,11 @@ impl Vec { #[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, 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 } } } From a74a28493a00900616d5e52cd85b8b6bae761935 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Tue, 15 Jul 2025 15:10:24 +0800 Subject: [PATCH 5/5] Add tests for UB check in `set_len`, `from_raw_parts_in`, `from_parts_in` Signed-off-by: xizheyin --- .../ui/precondition-checks/vec-from-parts.rs | 15 ++++++++++ .../precondition-checks/vec-from-raw-parts.rs | 29 +++++++++++++++++++ tests/ui/precondition-checks/vec-set-len.rs | 11 +++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/ui/precondition-checks/vec-from-parts.rs create mode 100644 tests/ui/precondition-checks/vec-from-raw-parts.rs create mode 100644 tests/ui/precondition-checks/vec-set-len.rs diff --git a/tests/ui/precondition-checks/vec-from-parts.rs b/tests/ui/precondition-checks/vec-from-parts.rs new file mode 100644 index 0000000000000..0bafb5aa715ef --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-parts.rs @@ -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 = 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); + } +} diff --git a/tests/ui/precondition-checks/vec-from-raw-parts.rs b/tests/ui/precondition-checks/vec-from-raw-parts.rs new file mode 100644 index 0000000000000..884d34c0a564b --- /dev/null +++ b/tests/ui/precondition-checks/vec-from-raw-parts.rs @@ -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::(); + // 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); + } +} diff --git a/tests/ui/precondition-checks/vec-set-len.rs b/tests/ui/precondition-checks/vec-set-len.rs new file mode 100644 index 0000000000000..0987e7fe02822 --- /dev/null +++ b/tests/ui/precondition-checks/vec-set-len.rs @@ -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 = Vec::with_capacity(5); + // Test set_len with length > capacity + unsafe { + vec.set_len(10); + } +}