Merge pull request #23 from dtolnay/malloc

Check arithmetic in malloc computations
This commit is contained in:
David Tolnay 2023-12-14 14:14:03 -08:00 committed by GitHub
commit 389373f0d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 5 deletions

View file

@ -54,6 +54,7 @@ mod libc {
#[macro_use]
mod externs {
use crate::libc;
use crate::ops::{die, ForceAdd as _, ForceInto as _};
use alloc::alloc::{self as rust, Layout};
use core::mem::{self, MaybeUninit};
use core::ptr;
@ -66,8 +67,10 @@ mod externs {
const MALLOC_ALIGN: usize = mem::align_of::<usize>();
pub unsafe fn malloc(size: libc::c_ulong) -> *mut libc::c_void {
let size = HEADER + size as usize;
let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
let size = HEADER.force_add(size.force_into());
let layout = Layout::from_size_align(size, MALLOC_ALIGN)
.ok()
.unwrap_or_else(die);
let memory = rust::alloc(layout);
if memory.is_null() {
rust::handle_alloc_error(layout);
@ -80,11 +83,13 @@ mod externs {
let mut memory = ptr.cast::<u8>().sub(HEADER);
let size = memory.cast::<usize>().read();
let layout = Layout::from_size_align_unchecked(size, MALLOC_ALIGN);
let new_size = HEADER + new_size as usize;
let new_size = HEADER.force_add(new_size.force_into());
let new_layout = Layout::from_size_align(new_size, MALLOC_ALIGN)
.ok()
.unwrap_or_else(die);
memory = rust::realloc(memory, layout, new_size);
if memory.is_null() {
let layout = Layout::from_size_align_unchecked(new_size, MALLOC_ALIGN);
rust::handle_alloc_error(layout);
rust::handle_alloc_error(new_layout);
}
memory.cast::<usize>().write(new_size);
memory.add(HEADER).cast()

View file

@ -26,6 +26,12 @@ impl ForceAdd for u64 {
}
}
impl ForceAdd for usize {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}
pub(crate) trait ForceMul: Sized {
fn force_mul(self, rhs: Self) -> Self;
}
@ -48,6 +54,23 @@ impl ForceMul for u64 {
}
}
pub(crate) trait ForceInto {
fn force_into<U>(self) -> U
where
Self: TryInto<U>;
}
impl<T> ForceInto for T {
fn force_into<U>(self) -> U
where
Self: TryInto<U>,
{
<Self as TryInto<U>>::try_into(self)
.ok()
.unwrap_or_else(die)
}
}
// Deterministically abort on arithmetic overflow, instead of wrapping and
// continuing with invalid behavior.
//