2 // alloc::heap::reallocate test.
4 // Ideally this would be revised to use no_std, but for now it serves
5 // well enough to reproduce (and illustrate) the bug from #16687.
7 #![feature(allocator_api)]
9 use std
::alloc
::{handle_alloc_error, AllocInit, AllocRef, Global, Layout, ReallocPlacement}
;
10 use std
::ptr
::{self, NonNull}
;
14 assert
!(test_triangle());
18 unsafe fn test_triangle() -> bool
{
19 static COUNT
: usize = 16;
20 let mut ascend
= vec
![ptr
::null_mut(); COUNT
];
21 let ascend
= &mut *ascend
;
22 static ALIGN
: usize = 1;
24 // Checks that `ascend` forms triangle of ascending size formed
25 // from pairs of rows (where each pair of rows is equally sized),
26 // and the elements of the triangle match their row-pair index.
27 unsafe fn sanity_check(ascend
: &[*mut u8]) {
28 for i
in 0..COUNT
/ 2 {
29 let (p0
, p1
, size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
31 assert_eq
!(*p0
.add(j
), i
as u8);
32 assert_eq
!(*p1
.add(j
), i
as u8);
37 static PRINT
: bool
= false;
39 unsafe fn allocate(layout
: Layout
) -> *mut u8 {
41 println
!("allocate({:?})", layout
);
45 .alloc(layout
, AllocInit
::Uninitialized
)
46 .unwrap_or_else(|_
| handle_alloc_error(layout
));
49 println
!("allocate({:?}) = {:?}", layout
, memory
.ptr
);
52 memory
.ptr
.cast().as_ptr()
55 unsafe fn deallocate(ptr
: *mut u8, layout
: Layout
) {
57 println
!("deallocate({:?}, {:?}", ptr
, layout
);
60 Global
.dealloc(NonNull
::new_unchecked(ptr
), layout
);
63 unsafe fn reallocate(ptr
: *mut u8, old
: Layout
, new
: Layout
) -> *mut u8 {
65 println
!("reallocate({:?}, old={:?}, new={:?})", ptr
, old
, new
);
68 let memory
= if new
.size() > old
.size() {
70 NonNull
::new_unchecked(ptr
),
73 ReallocPlacement
::MayMove
,
74 AllocInit
::Uninitialized
,
77 Global
.shrink(NonNull
::new_unchecked(ptr
), old
, new
.size(), ReallocPlacement
::MayMove
)
80 let memory
= memory
.unwrap_or_else(|_
| {
81 handle_alloc_error(Layout
::from_size_align_unchecked(new
.size(), old
.align()))
85 println
!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr
, old
, new
, memory
.ptr
);
87 memory
.ptr
.cast().as_ptr()
90 fn idx_to_size(i
: usize) -> usize {
94 // Allocate pairs of rows that form a triangle shape. (Hope is
95 // that at least two rows will be allocated near each other, so
96 // that we trigger the bug (a buffer overrun) in an observable
98 for i
in 0..COUNT
/ 2 {
99 let size
= idx_to_size(i
);
100 ascend
[2 * i
] = allocate(Layout
::from_size_align(size
, ALIGN
).unwrap());
101 ascend
[2 * i
+ 1] = allocate(Layout
::from_size_align(size
, ALIGN
).unwrap());
104 // Initialize each pair of rows to distinct value.
105 for i
in 0..COUNT
/ 2 {
106 let (p0
, p1
, size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
108 *p0
.add(j
) = i
as u8;
109 *p1
.add(j
) = i
as u8;
113 sanity_check(&*ascend
);
114 test_1(ascend
); // triangle -> square
115 test_2(ascend
); // square -> triangle
116 test_3(ascend
); // triangle -> square
117 test_4(ascend
); // square -> triangle
119 for i
in 0..COUNT
/ 2 {
120 let size
= idx_to_size(i
);
121 deallocate(ascend
[2 * i
], Layout
::from_size_align(size
, ALIGN
).unwrap());
122 deallocate(ascend
[2 * i
+ 1], Layout
::from_size_align(size
, ALIGN
).unwrap());
127 // Test 1: turn the triangle into a square (in terms of
128 // allocation; initialized portion remains a triangle) by
129 // realloc'ing each row from top to bottom, and checking all the
131 unsafe fn test_1(ascend
: &mut [*mut u8]) {
132 let new_size
= idx_to_size(COUNT
- 1);
133 let new
= Layout
::from_size_align(new_size
, ALIGN
).unwrap();
134 for i
in 0..COUNT
/ 2 {
135 let (p0
, p1
, old_size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
136 assert
!(old_size
< new_size
);
137 let old
= Layout
::from_size_align(old_size
, ALIGN
).unwrap();
139 ascend
[2 * i
] = reallocate(p0
, old
.clone(), new
.clone());
140 sanity_check(&*ascend
);
142 ascend
[2 * i
+ 1] = reallocate(p1
, old
.clone(), new
.clone());
143 sanity_check(&*ascend
);
147 // Test 2: turn the square back into a triangle, top to bottom.
148 unsafe fn test_2(ascend
: &mut [*mut u8]) {
149 let old_size
= idx_to_size(COUNT
- 1);
150 let old
= Layout
::from_size_align(old_size
, ALIGN
).unwrap();
151 for i
in 0..COUNT
/ 2 {
152 let (p0
, p1
, new_size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
153 assert
!(new_size
< old_size
);
154 let new
= Layout
::from_size_align(new_size
, ALIGN
).unwrap();
156 ascend
[2 * i
] = reallocate(p0
, old
.clone(), new
.clone());
157 sanity_check(&*ascend
);
159 ascend
[2 * i
+ 1] = reallocate(p1
, old
.clone(), new
.clone());
160 sanity_check(&*ascend
);
164 // Test 3: turn triangle into a square, bottom to top.
165 unsafe fn test_3(ascend
: &mut [*mut u8]) {
166 let new_size
= idx_to_size(COUNT
- 1);
167 let new
= Layout
::from_size_align(new_size
, ALIGN
).unwrap();
168 for i
in (0..COUNT
/ 2).rev() {
169 let (p0
, p1
, old_size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
170 assert
!(old_size
< new_size
);
171 let old
= Layout
::from_size_align(old_size
, ALIGN
).unwrap();
173 ascend
[2 * i
+ 1] = reallocate(p1
, old
.clone(), new
.clone());
174 sanity_check(&*ascend
);
176 ascend
[2 * i
] = reallocate(p0
, old
.clone(), new
.clone());
177 sanity_check(&*ascend
);
181 // Test 4: turn the square back into a triangle, bottom to top.
182 unsafe fn test_4(ascend
: &mut [*mut u8]) {
183 let old_size
= idx_to_size(COUNT
- 1);
184 let old
= Layout
::from_size_align(old_size
, ALIGN
).unwrap();
185 for i
in (0..COUNT
/ 2).rev() {
186 let (p0
, p1
, new_size
) = (ascend
[2 * i
], ascend
[2 * i
+ 1], idx_to_size(i
));
187 assert
!(new_size
< old_size
);
188 let new
= Layout
::from_size_align(new_size
, ALIGN
).unwrap();
190 ascend
[2 * i
+ 1] = reallocate(p1
, old
.clone(), new
.clone());
191 sanity_check(&*ascend
);
193 ascend
[2 * i
] = reallocate(p0
, old
.clone(), new
.clone());
194 sanity_check(&*ascend
);