Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d0c07aa

Browse files
committedMay 7, 2024
Move test_shrink_to_unwind to its own file.
This way, no other test can be tripped up by `test_shrink_to_unwind` changing the alloc error hook.
1 parent d77b1cc commit d0c07aa

File tree

4 files changed

+54
-55
lines changed

4 files changed

+54
-55
lines changed
 

‎alloc/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ rand_xorshift = "0.3.0"
2020
name = "alloctests"
2121
path = "tests/lib.rs"
2222

23+
[[test]]
24+
name = "vec_deque_alloc_error"
25+
path = "tests/vec_deque_alloc_error.rs"
26+
2327
[[bench]]
2428
name = "allocbenches"
2529
path = "benches/lib.rs"

‎alloc/src/collections/vec_deque/tests.rs

+1-54
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
#![feature(alloc_error_hook)]
2-
3-
use crate::alloc::{AllocError, Layout};
4-
use core::{iter::TrustedLen, ptr::NonNull};
5-
use std::{
6-
alloc::{set_alloc_error_hook, take_alloc_error_hook, System},
7-
panic::{catch_unwind, AssertUnwindSafe},
8-
};
1+
use core::iter::TrustedLen;
92

103
use super::*;
114

@@ -797,52 +790,6 @@ fn test_shrink_to() {
797790
}
798791
}
799792

800-
#[test]
801-
fn test_shrink_to_unwind() {
802-
// This tests that `shrink_to` leaves the deque in a consistent state when
803-
// the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369
804-
// but changed to hopefully not have any UB even if the test fails.
805-
806-
struct BadAlloc;
807-
808-
unsafe impl Allocator for BadAlloc {
809-
fn allocate(&self, l: Layout) -> Result<NonNull<[u8]>, AllocError> {
810-
// We allocate zeroed here so that the whole buffer of the deque
811-
// is always initialized. That way, even if the deque is left in
812-
// an inconsistent state, no uninitialized memory should be accessed.
813-
System.allocate_zeroed(l)
814-
}
815-
816-
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
817-
unsafe { System.deallocate(ptr, layout) }
818-
}
819-
820-
unsafe fn shrink(
821-
&self,
822-
_ptr: NonNull<u8>,
823-
_old_layout: Layout,
824-
_new_layout: Layout,
825-
) -> Result<NonNull<[u8]>, AllocError> {
826-
Err(AllocError)
827-
}
828-
}
829-
830-
// preserve the old error hook just in case.
831-
let old_error_hook = take_alloc_error_hook();
832-
set_alloc_error_hook(|_| panic!("alloc error"));
833-
834-
let mut v = VecDeque::with_capacity_in(15, BadAlloc);
835-
v.push_back(1);
836-
v.push_front(2);
837-
// This should unwind because it calls `BadAlloc::shrink` and then `handle_alloc_error` which unwinds.
838-
assert!(catch_unwind(AssertUnwindSafe(|| v.shrink_to_fit())).is_err());
839-
// This should only pass if the deque is left in a consistent state.
840-
assert_eq!(v, [2, 1]);
841-
842-
// restore the old error hook.
843-
set_alloc_error_hook(old_error_hook);
844-
}
845-
846793
#[test]
847794
fn test_shrink_to_fit() {
848795
// This test checks that every single combination of head and tail position,

‎alloc/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
// tidy-alphabetical-start
9393
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
9494
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
95-
#![cfg_attr(test, feature(alloc_error_hook))]
9695
#![cfg_attr(test, feature(is_sorted))]
9796
#![cfg_attr(test, feature(new_uninit))]
9897
#![feature(alloc_layout_extra)]

‎alloc/tests/vec_deque_alloc_error.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#![feature(alloc_error_hook, allocator_api)]
2+
3+
use std::{
4+
alloc::{set_alloc_error_hook, AllocError, Allocator, Layout, System},
5+
collections::VecDeque,
6+
panic::{catch_unwind, AssertUnwindSafe},
7+
ptr::NonNull,
8+
};
9+
10+
#[test]
11+
fn test_shrink_to_unwind() {
12+
// This tests that `shrink_to` leaves the deque in a consistent state when
13+
// the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369
14+
// but changed to hopefully not have any UB even if the test fails.
15+
16+
struct BadAlloc;
17+
18+
unsafe impl Allocator for BadAlloc {
19+
fn allocate(&self, l: Layout) -> Result<NonNull<[u8]>, AllocError> {
20+
// We allocate zeroed here so that the whole buffer of the deque
21+
// is always initialized. That way, even if the deque is left in
22+
// an inconsistent state, no uninitialized memory should be accessed.
23+
System.allocate_zeroed(l)
24+
}
25+
26+
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
27+
unsafe { System.deallocate(ptr, layout) }
28+
}
29+
30+
unsafe fn shrink(
31+
&self,
32+
_ptr: NonNull<u8>,
33+
_old_layout: Layout,
34+
_new_layout: Layout,
35+
) -> Result<NonNull<[u8]>, AllocError> {
36+
Err(AllocError)
37+
}
38+
}
39+
40+
set_alloc_error_hook(|_| panic!("alloc error"));
41+
42+
let mut v = VecDeque::with_capacity_in(15, BadAlloc);
43+
v.push_back(1);
44+
v.push_front(2);
45+
// This should unwind because it calls `BadAlloc::shrink` and then `handle_alloc_error` which unwinds.
46+
assert!(catch_unwind(AssertUnwindSafe(|| v.shrink_to_fit())).is_err());
47+
// This should only pass if the deque is left in a consistent state.
48+
assert_eq!(v, [2, 1]);
49+
}

0 commit comments

Comments
 (0)
Please sign in to comment.