]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | // alloc::heap::reallocate test. | |
12 | // | |
13 | // Ideally this would be revised to use no_std, but for now it serves | |
14 | // well enough to reproduce (and illustrate) the bug from #16687. | |
15 | ||
62682a34 | 16 | #![feature(heap_api, alloc, oom)] |
c34b1796 | 17 | |
1a4d82fc JJ |
18 | extern crate alloc; |
19 | ||
20 | use alloc::heap; | |
21 | use std::ptr; | |
1a4d82fc JJ |
22 | |
23 | fn main() { | |
24 | unsafe { | |
25 | assert!(test_triangle()); | |
26 | } | |
27 | } | |
28 | ||
29 | unsafe fn test_triangle() -> bool { | |
c34b1796 | 30 | static COUNT : usize = 16; |
c1a9b12d | 31 | let mut ascend = vec![ptr::null_mut(); COUNT]; |
85aaf69f | 32 | let ascend = &mut *ascend; |
c34b1796 | 33 | static ALIGN : usize = 1; |
1a4d82fc JJ |
34 | |
35 | // Checks that `ascend` forms triangle of ascending size formed | |
36 | // from pairs of rows (where each pair of rows is equally sized), | |
37 | // and the elements of the triangle match their row-pair index. | |
38 | unsafe fn sanity_check(ascend: &[*mut u8]) { | |
c34b1796 | 39 | for i in 0..COUNT / 2 { |
1a4d82fc | 40 | let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
c34b1796 AL |
41 | for j in 0..size { |
42 | assert_eq!(*p0.offset(j as isize), i as u8); | |
43 | assert_eq!(*p1.offset(j as isize), i as u8); | |
1a4d82fc JJ |
44 | } |
45 | } | |
46 | } | |
47 | ||
48 | static PRINT : bool = false; | |
49 | ||
c34b1796 | 50 | unsafe fn allocate(size: usize, align: usize) -> *mut u8 { |
1a4d82fc JJ |
51 | if PRINT { println!("allocate(size={} align={})", size, align); } |
52 | ||
53 | let ret = heap::allocate(size, align); | |
54 | if ret.is_null() { alloc::oom() } | |
55 | ||
56 | if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}", | |
c34b1796 | 57 | size, align, ret as usize); |
1a4d82fc JJ |
58 | } |
59 | ||
60 | ret | |
61 | } | |
c34b1796 | 62 | unsafe fn deallocate(ptr: *mut u8, size: usize, align: usize) { |
1a4d82fc | 63 | if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})", |
c34b1796 | 64 | ptr as usize, size, align); |
1a4d82fc JJ |
65 | } |
66 | ||
67 | heap::deallocate(ptr, size, align); | |
68 | } | |
c34b1796 | 69 | unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { |
1a4d82fc JJ |
70 | if PRINT { |
71 | println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})", | |
c34b1796 | 72 | ptr as usize, old_size, size, align); |
1a4d82fc JJ |
73 | } |
74 | ||
75 | let ret = heap::reallocate(ptr, old_size, size, align); | |
76 | if ret.is_null() { alloc::oom() } | |
77 | ||
78 | if PRINT { | |
79 | println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \ | |
80 | ret: 0x{:010x}", | |
c34b1796 | 81 | ptr as usize, old_size, size, align, ret as usize); |
1a4d82fc JJ |
82 | } |
83 | ret | |
84 | } | |
85 | ||
c34b1796 | 86 | fn idx_to_size(i: usize) -> usize { (i+1) * 10 } |
1a4d82fc JJ |
87 | |
88 | // Allocate pairs of rows that form a triangle shape. (Hope is | |
89 | // that at least two rows will be allocated near each other, so | |
90 | // that we trigger the bug (a buffer overrun) in an observable | |
91 | // way.) | |
c34b1796 | 92 | for i in 0..COUNT / 2 { |
1a4d82fc JJ |
93 | let size = idx_to_size(i); |
94 | ascend[2*i] = allocate(size, ALIGN); | |
95 | ascend[2*i+1] = allocate(size, ALIGN); | |
96 | } | |
97 | ||
98 | // Initialize each pair of rows to distinct value. | |
c34b1796 | 99 | for i in 0..COUNT / 2 { |
1a4d82fc | 100 | let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
85aaf69f | 101 | for j in 0..size { |
c34b1796 AL |
102 | *p0.offset(j as isize) = i as u8; |
103 | *p1.offset(j as isize) = i as u8; | |
1a4d82fc JJ |
104 | } |
105 | } | |
106 | ||
85aaf69f | 107 | sanity_check(&*ascend); |
1a4d82fc JJ |
108 | test_1(ascend); // triangle -> square |
109 | test_2(ascend); // square -> triangle | |
110 | test_3(ascend); // triangle -> square | |
111 | test_4(ascend); // square -> triangle | |
112 | ||
c34b1796 | 113 | for i in 0..COUNT / 2 { |
1a4d82fc JJ |
114 | let size = idx_to_size(i); |
115 | deallocate(ascend[2*i], size, ALIGN); | |
116 | deallocate(ascend[2*i+1], size, ALIGN); | |
117 | } | |
118 | ||
119 | return true; | |
120 | ||
121 | // Test 1: turn the triangle into a square (in terms of | |
122 | // allocation; initialized portion remains a triangle) by | |
123 | // realloc'ing each row from top to bottom, and checking all the | |
124 | // rows as we go. | |
125 | unsafe fn test_1(ascend: &mut [*mut u8]) { | |
126 | let new_size = idx_to_size(COUNT-1); | |
c34b1796 | 127 | for i in 0..COUNT / 2 { |
1a4d82fc JJ |
128 | let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
129 | assert!(old_size < new_size); | |
130 | ||
131 | ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); | |
85aaf69f | 132 | sanity_check(&*ascend); |
1a4d82fc JJ |
133 | |
134 | ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); | |
85aaf69f | 135 | sanity_check(&*ascend); |
1a4d82fc JJ |
136 | } |
137 | } | |
138 | ||
139 | // Test 2: turn the square back into a triangle, top to bottom. | |
140 | unsafe fn test_2(ascend: &mut [*mut u8]) { | |
141 | let old_size = idx_to_size(COUNT-1); | |
c34b1796 | 142 | for i in 0..COUNT / 2 { |
1a4d82fc JJ |
143 | let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
144 | assert!(new_size < old_size); | |
145 | ||
146 | ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); | |
85aaf69f | 147 | sanity_check(&*ascend); |
1a4d82fc JJ |
148 | |
149 | ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); | |
85aaf69f | 150 | sanity_check(&*ascend); |
1a4d82fc JJ |
151 | } |
152 | } | |
153 | ||
154 | // Test 3: turn triangle into a square, bottom to top. | |
155 | unsafe fn test_3(ascend: &mut [*mut u8]) { | |
156 | let new_size = idx_to_size(COUNT-1); | |
c34b1796 | 157 | for i in (0..COUNT / 2).rev() { |
1a4d82fc JJ |
158 | let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
159 | assert!(old_size < new_size); | |
160 | ||
161 | ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); | |
85aaf69f | 162 | sanity_check(&*ascend); |
1a4d82fc JJ |
163 | |
164 | ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); | |
85aaf69f | 165 | sanity_check(&*ascend); |
1a4d82fc JJ |
166 | } |
167 | } | |
168 | ||
169 | // Test 4: turn the square back into a triangle, bottom to top. | |
170 | unsafe fn test_4(ascend: &mut [*mut u8]) { | |
171 | let old_size = idx_to_size(COUNT-1); | |
c34b1796 | 172 | for i in (0..COUNT / 2).rev() { |
1a4d82fc JJ |
173 | let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); |
174 | assert!(new_size < old_size); | |
175 | ||
176 | ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); | |
85aaf69f | 177 | sanity_check(&*ascend); |
1a4d82fc JJ |
178 | |
179 | ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); | |
85aaf69f | 180 | sanity_check(&*ascend); |
1a4d82fc JJ |
181 | } |
182 | } | |
183 | } |