diff options
| author | bors <bors@rust-lang.org> | 2022-09-19 14:06:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-09-19 14:06:23 +0000 |
| commit | a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52 (patch) | |
| tree | 2de5a3c571f7f5b54f4922b644f72f33786eb0e0 /library | |
| parent | b31188e88b245f48b364c6cb186b821bd472bd8a (diff) | |
| parent | 7358a9b03e5d22ea4d74d89cb00d3985fc89c773 (diff) | |
| download | rust-1.64.0.tar.gz rust-1.64.0.zip | |
Auto merge of #102018 - pietroalbini:pa-1.64.0, r=pietroalbini 1.64.0
[stable] Prepare 1.64.0 release This PR prepares the 1.64.0 stable release builds. In addition to bumping the channel and including the latest release notes changes, this PR also backports the following PRs: * #100852 * #101366 * #101468 * #101922 This PR also reverts the following PRs, as decided in https://github.com/rust-lang/rust/issues/101899#issuecomment-1250996783: * https://github.com/rust-lang/rust/pull/95295 * https://github.com/rust-lang/rust/pull/99136 (followup to the previous PR) r? `@ghost` cc `@rust-lang/release`
Diffstat (limited to 'library')
| -rw-r--r-- | library/alloc/tests/string.rs | 126 | ||||
| -rw-r--r-- | library/alloc/tests/vec.rs | 166 | ||||
| -rw-r--r-- | library/alloc/tests/vec_deque.rs | 161 | ||||
| -rw-r--r-- | library/core/src/alloc/layout.rs | 76 | ||||
| -rw-r--r-- | library/core/src/mem/valid_align.rs | 11 | ||||
| -rw-r--r-- | library/std/src/sys/windows/path.rs | 9 | ||||
| -rw-r--r-- | library/std/src/sys/windows/path/tests.rs | 29 |
7 files changed, 369 insertions, 209 deletions
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 99d1296a4c9..b6836fdc88e 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -693,6 +693,12 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = usize::BITS < 64; + { // Note: basic stuff is checked by test_reserve let mut empty_string: String = String::new(); @@ -706,19 +712,35 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + // Check isize::MAX + 1 is an OOM + assert_matches!( + empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + + // Check usize::MAX is an OOM + assert_matches!( + empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); + } } { @@ -731,13 +753,19 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -757,6 +785,8 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; + let guards_against_isize = usize::BITS < 64; + { let mut empty_string: String = String::new(); @@ -769,17 +799,31 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - assert_matches!( - empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + assert_matches!( + empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + + assert_matches!( + empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); + } } { @@ -795,13 +839,19 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index d94da8f5f5a..b797e237535 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1527,6 +1527,12 @@ fn test_try_reserve() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = usize::BITS < 64; + { // Note: basic stuff is checked by test_reserve let mut empty_bytes: Vec<u8> = Vec::new(); @@ -1540,19 +1546,35 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + // Check isize::MAX + 1 is an OOM + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + + // Check usize::MAX is an OOM + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); + } } { @@ -1565,13 +1587,19 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1592,13 +1620,19 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1618,6 +1652,8 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; + let guards_against_isize = size_of::<usize>() < 8; + { let mut empty_bytes: Vec<u8> = Vec::new(); @@ -1630,17 +1666,31 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(AllocError { .. }), + "usize::MAX should trigger an OOM!" + ); + } } { @@ -1656,13 +1706,19 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1683,13 +1739,19 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 019d73c0b16..89cc7f905be 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,6 +2,7 @@ use std::assert_matches::assert_matches; use std::collections::TryReserveErrorKind::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; +use std::mem::size_of; use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -1160,6 +1161,12 @@ fn test_try_reserve() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; + // On 16/32-bit, we check that allocations don't exceed isize::MAX, + // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. + // Any platform that succeeds for these requests is technically broken with + // ptr::offset because LLVM is the worst. + let guards_against_isize = size_of::<usize>() < 8; + { // Note: basic stuff is checked by test_reserve let mut empty_bytes: VecDeque<u8> = VecDeque::new(); @@ -1173,19 +1180,31 @@ fn test_try_reserve() { panic!("isize::MAX shouldn't trigger an overflow!"); } - // Check isize::MAX + 1 does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - // Check usize::MAX does count as overflow - assert_matches!( - empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + // Check isize::MAX + 1 does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + // Check usize::MAX does count as overflow + assert_matches!( + empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + // Check isize::MAX is an OOM + // VecDeque starts with capacity 7, always adds 1 to the capacity + // and also rounds the number to next power of 2 so this is the + // furthest we can go without triggering CapacityOverflow + assert_matches!( + empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } } { @@ -1198,13 +1217,19 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } // Should always overflow in the add-to-len assert_matches!( ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()), @@ -1225,13 +1250,19 @@ fn test_try_reserve() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } // Should fail in the mul-by-size assert_matches!( ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()), @@ -1251,6 +1282,8 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1; const MAX_USIZE: usize = usize::MAX; + let guards_against_isize = size_of::<usize>() < 8; + { let mut empty_bytes: VecDeque<u8> = VecDeque::new(); @@ -1263,17 +1296,29 @@ fn test_try_reserve_exact() { panic!("isize::MAX shouldn't trigger an overflow!"); } - assert_matches!( - empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - - assert_matches!( - empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), - Err(CapacityOverflow), - "usize::MAX should trigger an overflow!" - ); + if guards_against_isize { + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + + assert_matches!( + empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), + Err(CapacityOverflow), + "usize::MAX should trigger an overflow!" + ); + } else { + // Check isize::MAX is an OOM + // VecDeque starts with capacity 7, always adds 1 to the capacity + // and also rounds the number to next power of 2 so this is the + // furthest we can go without triggering CapacityOverflow + assert_matches!( + empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } } { @@ -1289,13 +1334,19 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } assert_matches!( ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()), Err(CapacityOverflow), @@ -1316,13 +1367,19 @@ fn test_try_reserve_exact() { { panic!("isize::MAX shouldn't trigger an overflow!"); } - - assert_matches!( - ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), - Err(CapacityOverflow), - "isize::MAX + 1 should trigger an overflow!" - ); - + if guards_against_isize { + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(CapacityOverflow), + "isize::MAX + 1 should trigger an overflow!" + ); + } else { + assert_matches!( + ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()), + Err(AllocError { .. }), + "isize::MAX + 1 should trigger an OOM!" + ); + } assert_matches!( ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()), Err(CapacityOverflow), diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 59ebe5fbe02..2f378836cbb 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -1,9 +1,3 @@ -// Seemingly inconsequential code changes to this file can lead to measurable -// performance impact on compilation times, due at least in part to the fact -// that the layout code gets called from many instantiations of the various -// collections, resulting in having to optimize down excess IR multiple times. -// Your performance intuition is useless. Run perf. - use crate::cmp; use crate::fmt; use crate::mem::{self, ValidAlign}; @@ -58,8 +52,8 @@ impl Layout { /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, - /// must not overflow isize (i.e., the rounded value must be - /// less than or equal to `isize::MAX`). + /// must not overflow (i.e., the rounded value must be less than + /// or equal to `usize::MAX`). #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[inline] @@ -68,13 +62,6 @@ impl Layout { return Err(LayoutError); } - // SAFETY: just checked that align is a power of two. - Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) }) - } - - /// Internal helper constructor to skip revalidating alignment validity. - #[inline] - const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> { // (power-of-two implies align != 0.) // Rounded up size is: @@ -89,12 +76,13 @@ impl Layout { // // Above implies that checking for summation overflow is both // necessary and sufficient. - if size > isize::MAX as usize - (align.as_nonzero().get() - 1) { + if size > usize::MAX - (align - 1) { return Err(LayoutError); } - // SAFETY: Layout::size invariants checked above. - Ok(Layout { size, align }) + // SAFETY: the conditions for `from_size_align_unchecked` have been + // checked above. + unsafe { Ok(Layout::from_size_align_unchecked(size, align)) } } /// Creates a layout, bypassing all checks. @@ -108,8 +96,8 @@ impl Layout { #[must_use] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - // SAFETY: the caller is required to uphold the preconditions. - unsafe { Layout { size, align: ValidAlign::new_unchecked(align) } } + // SAFETY: the caller must ensure that `align` is a power of two. + Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } } } /// The minimum size in bytes for a memory block of this layout. @@ -138,9 +126,10 @@ impl Layout { #[inline] pub const fn new<T>() -> Self { let (size, align) = size_align::<T>(); - // SAFETY: if the type is instantiated, rustc already ensures that its - // layout is valid. Use the unchecked constructor to avoid inserting a - // panicking codepath that needs to be optimized out. + // SAFETY: the align is guaranteed by Rust to be a power of two and + // the size+align combo is guaranteed to fit in our address space. As a + // result use the unchecked constructor here to avoid inserting code + // that panics if it isn't optimized well enough. unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -152,6 +141,7 @@ impl Layout { #[inline] pub fn for_value<T: ?Sized>(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -186,6 +176,7 @@ impl Layout { pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; + debug_assert!(Layout::from_size_align(size, align).is_ok()); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } @@ -285,11 +276,12 @@ impl Layout { let pad = self.padding_needed_for(self.align()); // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow isize (i.e., the rounded value must be - // > less than or equal to `isize::MAX`) + // > must not overflow (i.e., the rounded value must be less than + // > `usize::MAX`) let new_size = self.size() + pad; - // SAFETY: padded size is guaranteed to not exceed `isize::MAX`. + // SAFETY: self.align is already known to be valid and new_size has been + // padded already. unsafe { Layout::from_size_align_unchecked(new_size, self.align()) } } @@ -306,13 +298,14 @@ impl Layout { pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, - // > must not overflow isize (i.e., the rounded value must be - // > less than or equal to `isize::MAX`) + // > must not overflow (i.e., the rounded value must be less than + // > `usize::MAX`) let padded_size = self.size() + self.padding_needed_for(self.align()); let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_valid_align(alloc_size, self.align).map(|layout| (layout, padded_size)) + // SAFETY: self.align is already known to be valid and alloc_size has been + // padded already. + unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) } } /// Creates a layout describing the record for `self` followed by @@ -363,14 +356,13 @@ impl Layout { #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { - let new_align = cmp::max(self.align, next.align); + let new_align = cmp::max(self.align(), next.align()); let pad = self.padding_needed_for(next.align()); let offset = self.size().checked_add(pad).ok_or(LayoutError)?; let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - let layout = Layout::from_size_valid_align(new_size, new_align)?; + let layout = Layout::from_size_align(new_size, new_align)?; Ok((layout, offset)) } @@ -390,8 +382,7 @@ impl Layout { #[inline] pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> { let size = self.size().checked_mul(n).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_valid_align(size, self.align) + Layout::from_size_align(size, self.align()) } /// Creates a layout describing the record for `self` followed by @@ -404,8 +395,7 @@ impl Layout { #[inline] pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> { let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_valid_align(new_size, self.align) + Layout::from_size_align(new_size, self.align()) } /// Creates a layout describing the record for a `[T; n]`. @@ -415,8 +405,16 @@ impl Layout { #[inline] pub fn array<T>(n: usize) -> Result<Self, LayoutError> { let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_valid_align(array_size, ValidAlign::of::<T>()) + + // SAFETY: + // - Size: `array_size` cannot be too big because `size_of::<T>()` must + // be a multiple of `align_of::<T>()`. Therefore, `array_size` + // rounded up to the nearest multiple of `align_of::<T>()` is just + // `array_size`. And `array_size` cannot be too big because it was + // just checked by the `checked_mul()`. + // - Alignment: `align_of::<T>()` will always give an acceptable + // (non-zero, power of two) alignment. + Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) }) } } diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index 4ce6d13cf90..fcfa95120df 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -1,5 +1,4 @@ use crate::convert::TryFrom; -use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -27,8 +26,7 @@ impl ValidAlign { /// It must *not* be zero. #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - // SAFETY: Precondition passed to the caller. - unsafe { assert_unsafe_precondition!(align.is_power_of_two()) }; + debug_assert!(align.is_power_of_two()); // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. @@ -48,13 +46,6 @@ impl ValidAlign { pub(crate) fn log2(self) -> u32 { self.as_nonzero().trailing_zeros() } - - /// Returns the alignment for a type. - #[inline] - pub(crate) fn of<T>() -> Self { - // SAFETY: rustc ensures that type alignment is always a power of two. - unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) } - } } impl fmt::Debug for ValidAlign { diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index a0f82207099..beeca1917a9 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -198,14 +198,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { match path.bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { - let mut separator_end = separator_start + 1; - - // a series of multiple separator characters is treated as a single separator, - // except in verbatim paths - while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end]) - { - separator_end += 1; - } + let separator_end = separator_start + 1; let component = &path.bytes()[..separator_start]; diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index 2f7ec433bf2..6eab38cabfd 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -31,16 +31,6 @@ fn test_parse_next_component() { parse_next_component(OsStr::new(r"servershare"), false), (OsStr::new(r"servershare"), OsStr::new("")) ); - - assert_eq!( - parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false), - (OsStr::new(r"server"), OsStr::new(r"share")) - ); - - assert_eq!( - parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true), - (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share")) - ); } #[test] @@ -126,3 +116,22 @@ fn test_windows_prefix_components() { assert_eq!(drive.as_os_str(), OsStr::new("C:")); assert_eq!(components.as_path(), Path::new("")); } + +/// See #101358. +/// +/// Note that the exact behaviour here may change in the future. +/// In which case this test will need to adjusted. +#[test] +fn broken_unc_path() { + use crate::path::Component; + + let mut components = Path::new(r"\\foo\\bar\\").components(); + assert_eq!(components.next(), Some(Component::RootDir)); + assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); + assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); + + let mut components = Path::new("//foo//bar//").components(); + assert_eq!(components.next(), Some(Component::RootDir)); + assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); + assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); +} |
