Skip to content

Commit 3c84484

Browse files
author
Jethro Beekman
committed
Fix integer overflows
1 parent 9c1e1e2 commit 3c84484

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ features = ['global']
1616

1717
[lib]
1818
doctest = false
19-
test = false
2019

2120
[target.'cfg(all(unix, not(target_arch = "wasm32")))'.dependencies]
2221
libc = { version = "0.2", default-features = false }

src/dlmalloc.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ fn align_up(a: usize, alignment: usize) -> usize {
9292
}
9393

9494
fn left_bits(x: u32) -> u32 {
95-
(x << 1) | (!(x << 1) + 1)
95+
(x << 1) | (!(x << 1)).wrapping_add(1)
9696
}
9797

9898
fn least_bit(x: u32) -> u32 {
@@ -150,7 +150,23 @@ impl Dlmalloc {
150150

151151
// TODO: dox
152152
fn max_request(&self) -> usize {
153-
(!self.min_chunk_size() + 1) << 2
153+
// min_sys_alloc_space: the largest `X` such that
154+
// pad_request(X - 1) -- minus 1, because requests of exactly
155+
// `max_request` will not be honored
156+
// + self.top_foot_size()
157+
// + self.malloc_alignment()
158+
// + DEFAULT_GRANULARITY
159+
// ==
160+
// usize::MAX
161+
let min_sys_alloc_space = (
162+
(!0 - (DEFAULT_GRANULARITY + self.top_foot_size() + self.malloc_alignment()) + 1)
163+
& !self.malloc_alignment()
164+
) - self.chunk_overhead() + 1;
165+
166+
cmp::min(
167+
(!self.min_chunk_size() + 1) << 2,
168+
min_sys_alloc_space
169+
)
154170
}
155171

156172
fn pad_request(&self, amt: usize) -> usize {
@@ -334,6 +350,7 @@ impl Dlmalloc {
334350

335351
unsafe fn sys_alloc(&mut self, size: usize) -> *mut u8 {
336352
self.check_malloc_state();
353+
// keep in sync with max_request
337354
let asize = align_up(size + self.top_foot_size() + self.malloc_alignment(),
338355
DEFAULT_GRANULARITY);
339356

@@ -1751,3 +1768,44 @@ impl Segment {
17511768
(*seg).base.offset((*seg).size as isize)
17521769
}
17531770
}
1771+
1772+
#[cfg(test)]
1773+
mod tests {
1774+
use super::*;
1775+
1776+
// Prime the allocator with some allocations such that there will be free
1777+
// chunks in the treemap
1778+
unsafe fn setup_treemap(a: &mut Dlmalloc) {
1779+
let large_request_size = NSMALLBINS * (1 << SMALLBIN_SHIFT);
1780+
assert!(!a.is_small(large_request_size));
1781+
let large_request1 = a.malloc(large_request_size);
1782+
assert_ne!(large_request1, ptr::null_mut());
1783+
let large_request2 = a.malloc(large_request_size);
1784+
assert_ne!(large_request2, ptr::null_mut());
1785+
a.free(large_request1);
1786+
assert_ne!(a.treemap, 0);
1787+
}
1788+
1789+
#[test]
1790+
// Test allocating, with a non-empty treemap, a specific size that used to
1791+
// trigger an integer overflow bug
1792+
fn treemap_alloc_overflow_minimal() {
1793+
let mut a = DLMALLOC_INIT;
1794+
unsafe {
1795+
setup_treemap(&mut a);
1796+
let min_idx31_size = (0xc000 << TREEBIN_SHIFT) - a.chunk_overhead() + 1;
1797+
assert_ne!(a.malloc(min_idx31_size), ptr::null_mut());
1798+
}
1799+
}
1800+
1801+
#[test]
1802+
// Test allocating the maximum request size with a non-empty treemap
1803+
fn treemap_alloc_max() {
1804+
let mut a = DLMALLOC_INIT;
1805+
unsafe {
1806+
setup_treemap(&mut a);
1807+
let max_request_size = a.max_request() - 1;
1808+
assert_eq!(a.malloc(max_request_size), ptr::null_mut());
1809+
}
1810+
}
1811+
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ use core::alloc::{Alloc, Layout, AllocErr};
2222
use core::cmp;
2323
use core::ptr;
2424

25-
#[cfg(feature = "global")]
25+
#[cfg(all(feature = "global", not(test)))]
2626
pub use self::global::GlobalDlmalloc;
2727

28-
#[cfg(feature = "global")]
28+
#[cfg(all(feature = "global", not(test)))]
2929
mod global;
3030
mod dlmalloc;
3131

0 commit comments

Comments
 (0)