Skip to content

Commit 16d538c

Browse files
committed
auto merge of #16706 : pnkfelix/rust/fsk-fix-nojem-realloc, r=thestinger
Copy only up to `min(new_size, old_size)` when doing reallocate. This was a bug when running with jemalloc disabled. Fix #16687
2 parents c556ca9 + b1f7d3a commit 16d538c

File tree

2 files changed

+169
-1
lines changed

2 files changed

+169
-1
lines changed

src/liballoc/heap.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ mod imp {
208208

209209
#[cfg(not(jemalloc), unix)]
210210
mod imp {
211+
use core::cmp;
211212
use core::mem;
212213
use core::ptr;
213214
use libc;
@@ -248,7 +249,7 @@ mod imp {
248249
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
249250
old_size: uint) -> *mut u8 {
250251
let new_ptr = allocate(size, align);
251-
ptr::copy_memory(new_ptr, ptr as *const u8, old_size);
252+
ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
252253
deallocate(ptr, old_size, align);
253254
return new_ptr;
254255
}

src/test/run-pass/realloc-16687.rs

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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+
16+
extern crate alloc;
17+
18+
use alloc::heap;
19+
use std::ptr;
20+
21+
fn main() {
22+
unsafe {
23+
assert!(test_triangle());
24+
}
25+
}
26+
27+
unsafe fn test_triangle() -> bool {
28+
static COUNT : uint = 16;
29+
let mut ascend = Vec::from_elem(COUNT, ptr::mut_null());
30+
let ascend = ascend.as_mut_slice();
31+
static ALIGN : uint = 1;
32+
33+
// Checks that `ascend` forms triangle of acending size formed
34+
// from pairs of rows (where each pair of rows is equally sized),
35+
// and the elements of the triangle match their row-pair index.
36+
unsafe fn sanity_check(ascend: &[*mut u8]) {
37+
for i in range(0u, COUNT / 2) {
38+
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
39+
for j in range(0u, size) {
40+
assert_eq!(*p0.offset(j as int), i as u8);
41+
assert_eq!(*p1.offset(j as int), i as u8);
42+
}
43+
}
44+
}
45+
46+
static PRINT : bool = false;
47+
48+
unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
49+
if PRINT { println!("allocate(size={:u} align={:u})", size, align); }
50+
51+
let ret = heap::allocate(size, align);
52+
53+
if PRINT { println!("allocate(size={:u} align={:u}) ret: 0x{:010x}",
54+
size, align, ret as uint);
55+
}
56+
57+
ret
58+
}
59+
unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
60+
old_size: uint) -> *mut u8 {
61+
if PRINT {
62+
println!("reallocate(ptr=0x{:010x} size={:u} align={:u} old_size={:u})",
63+
ptr as uint, size, align, old_size);
64+
}
65+
66+
let ret = heap::reallocate(ptr, size, align, old_size);
67+
68+
if PRINT {
69+
println!("reallocate(ptr=0x{:010x} size={:u} align={:u} old_size={:u}) \
70+
ret: 0x{:010x}",
71+
ptr as uint, size, align, old_size, ret as uint);
72+
}
73+
ret
74+
}
75+
76+
fn idx_to_size(i: uint) -> uint { (i+1) * 10 }
77+
78+
// Allocate pairs of rows that form a triangle shape. (Hope is
79+
// that at least two rows will be allocated near each other, so
80+
// that we trigger the bug (a buffer overrun) in an observable
81+
// way.)
82+
for i in range(0u, COUNT / 2) {
83+
let size = idx_to_size(i);
84+
ascend[2*i] = allocate(size, ALIGN);
85+
ascend[2*i+1] = allocate(size, ALIGN);
86+
}
87+
88+
// Initialize each pair of rows to distinct value.
89+
for i in range(0u, COUNT / 2) {
90+
let (p0, p1, size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
91+
for j in range(0, size) {
92+
*p0.offset(j as int) = i as u8;
93+
*p1.offset(j as int) = i as u8;
94+
}
95+
}
96+
97+
sanity_check(ascend.as_slice());
98+
test_1(ascend);
99+
test_2(ascend);
100+
test_3(ascend);
101+
test_4(ascend);
102+
103+
return true;
104+
105+
// Test 1: turn the triangle into a square (in terms of
106+
// allocation; initialized portion remains a triangle) by
107+
// realloc'ing each row from top to bottom, and checking all the
108+
// rows as we go.
109+
unsafe fn test_1(ascend: &mut [*mut u8]) {
110+
let new_size = idx_to_size(COUNT-1);
111+
for i in range(0u, COUNT / 2) {
112+
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
113+
assert!(old_size < new_size);
114+
115+
ascend[2*i] = reallocate(p0, new_size, ALIGN, old_size);
116+
sanity_check(ascend.as_slice());
117+
118+
ascend[2*i+1] = reallocate(p1, new_size, ALIGN, old_size);
119+
sanity_check(ascend.as_slice());
120+
}
121+
}
122+
123+
// Test 2: turn the square back into a triangle, top to bottom.
124+
unsafe fn test_2(ascend: &mut [*mut u8]) {
125+
let old_size = idx_to_size(COUNT-1);
126+
for i in range(0u, COUNT / 2) {
127+
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
128+
assert!(new_size < old_size);
129+
130+
ascend[2*i] = reallocate(p0, new_size, ALIGN, old_size);
131+
sanity_check(ascend.as_slice());
132+
133+
ascend[2*i+1] = reallocate(p1, new_size, ALIGN, old_size);
134+
sanity_check(ascend.as_slice());
135+
}
136+
}
137+
138+
// Test 3: turn triangle into a square, bottom to top.
139+
unsafe fn test_3(ascend: &mut [*mut u8]) {
140+
let new_size = idx_to_size(COUNT-1);
141+
for i in range(0u, COUNT / 2).rev() {
142+
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
143+
assert!(old_size < new_size);
144+
145+
ascend[2*i+1] = reallocate(p1, new_size, ALIGN, old_size);
146+
sanity_check(ascend.as_slice());
147+
148+
ascend[2*i] = reallocate(p0, new_size, ALIGN, old_size);
149+
sanity_check(ascend.as_slice());
150+
}
151+
}
152+
153+
// Test 4: turn the square back into a triangle, bottom to top.
154+
unsafe fn test_4(ascend: &mut [*mut u8]) {
155+
let old_size = idx_to_size(COUNT-1);
156+
for i in range(0u, COUNT / 2).rev() {
157+
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
158+
assert!(new_size < old_size);
159+
160+
ascend[2*i+1] = reallocate(p1, new_size, ALIGN, old_size);
161+
sanity_check(ascend.as_slice());
162+
163+
ascend[2*i] = reallocate(p0, new_size, ALIGN, old_size);
164+
sanity_check(ascend.as_slice());
165+
}
166+
}
167+
}

0 commit comments

Comments
 (0)