Skip to content

Commit e53e771

Browse files
committed
Detect when overflow would happen and panic
1 parent f12de17 commit e53e771

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

src/lib.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ impl Bump {
404404
/// Allocate an object in this `Bump` and return an exclusive reference to
405405
/// it.
406406
///
407+
/// ## Panics
408+
///
409+
/// Panics if reserving space for `T` would cause an overflow.
410+
///
407411
/// ## Example
408412
///
409413
/// ```
@@ -423,8 +427,17 @@ impl Bump {
423427
}
424428
}
425429

430+
/// Allocate space for an object with the given `Layout`.
431+
///
432+
/// The returned pointer points at uninitialized memory, and should be
433+
/// initialized with
434+
/// [`std::ptr::write`](https://doc.rust-lang.org/stable/std/ptr/fn.write.html).
435+
///
436+
/// ## Panics
437+
///
438+
/// Panics if reserving space for `T` would cause an overflow.
426439
#[inline(always)]
427-
fn alloc_layout(&self, layout: Layout) -> NonNull<u8> {
440+
pub fn alloc_layout(&self, layout: Layout) -> NonNull<u8> {
428441
unsafe {
429442
let footer = self.current_chunk_footer.get();
430443
let footer = footer.as_ref();
@@ -433,7 +446,11 @@ impl Bump {
433446
let end = footer as *const _ as usize;
434447
debug_assert!(ptr <= end);
435448

436-
let new_ptr = ptr + layout.size();
449+
let new_ptr = match ptr.checked_add(layout.size()) {
450+
Some(p) => p,
451+
None => self.overflow(),
452+
};
453+
437454
if new_ptr <= end {
438455
let p = ptr as *mut u8;
439456
debug_assert!(new_ptr <= footer as *const _ as usize);
@@ -445,6 +462,12 @@ impl Bump {
445462
self.alloc_layout_slow(layout)
446463
}
447464

465+
#[inline(never)]
466+
#[cold]
467+
fn overflow(&self) -> ! {
468+
panic!("allocation too large, caused overflow")
469+
}
470+
448471
// Slow path allocation for when we need to allocate a new chunk from the
449472
// parent bump set because there isn't enough room in our current chunk.
450473
#[inline(never)]

tests/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
extern crate bumpalo;
22

33
use bumpalo::Bump;
4+
use std::alloc::Layout;
45
use std::mem;
56
use std::slice;
7+
use std::usize;
68

79
#[test]
810
fn can_iterate_over_allocated_things() {
@@ -59,3 +61,26 @@ fn can_iterate_over_allocated_things() {
5961

6062
assert!(seen.iter().all(|s| *s));
6163
}
64+
65+
#[test]
66+
#[should_panic(expected = "allocation too large, caused overflow")]
67+
fn alloc_overflow() {
68+
let bump = Bump::new();
69+
let x = bump.alloc(0_u8);
70+
let p = x as *mut u8 as usize;
71+
72+
// A size guaranteed to overflow.
73+
let size = usize::MAX - p + 1;
74+
let align = 1;
75+
let layout = match Layout::from_size_align(size, align) {
76+
Err(e) => {
77+
// Return on error so that we don't panic and the test fails.
78+
eprintln!("Layout::from_size_align errored: {}", e);
79+
return;
80+
}
81+
Ok(l) => l,
82+
};
83+
84+
// This should panic.
85+
bump.alloc_layout(layout);
86+
}

0 commit comments

Comments
 (0)