use crate::backend::Backend;
use crate::error::*;
use crate::state::State;
use llvm_ir::*;
use log::warn;
const MAX_ALLOCATION_SIZE_BYTES: u64 = 1 << 20;
pub fn malloc<B: Backend>(state: &mut State<B>, num_bytes: &Operand) -> Result<B::BV> {
let num_bytes = try_as_u64(num_bytes).unwrap_or(MAX_ALLOCATION_SIZE_BYTES);
if num_bytes > MAX_ALLOCATION_SIZE_BYTES {
warn!("warning: encountered an allocation of {} bytes, greater than the assumed max of {}. \
Since this allocation is constant-sized, it's fine in this case, but does draw into question the assumption.", num_bytes, MAX_ALLOCATION_SIZE_BYTES);
}
let num_bits = num_bytes * 8;
Ok(state.allocate(num_bits))
}
pub fn zalloc<B: Backend>(state: &mut State<B>, num_bytes: &Operand) -> Result<B::BV> {
let num_bytes = try_as_u64(num_bytes).unwrap_or(MAX_ALLOCATION_SIZE_BYTES);
if num_bytes > MAX_ALLOCATION_SIZE_BYTES {
warn!("warning: encountered an allocation of {} bytes, greater than the assumed max of {}. \
Since this allocation is constant-sized, it's fine in this case, but does draw into question the assumption.", num_bytes, MAX_ALLOCATION_SIZE_BYTES);
}
let num_bits = num_bytes * 8;
let addr = state.allocate(num_bits);
state.write(&addr, state.zero(num_bits as u32))?;
Ok(addr)
}
pub fn calloc<B: Backend>(state: &mut State<B>, a: &Operand, b: &Operand) -> Result<B::BV> {
let num_bytes = match (try_as_u64(a), try_as_u64(b)) {
(Some(a), Some(b)) => a * b,
_ => MAX_ALLOCATION_SIZE_BYTES,
};
if num_bytes > MAX_ALLOCATION_SIZE_BYTES {
warn!("warning: encountered an allocation of {} bytes, greater than the assumed max of {}. \
Since this allocation is constant-sized, it's fine in this case, but does draw into question the assumption.", num_bytes, MAX_ALLOCATION_SIZE_BYTES);
}
let num_bits = num_bytes * 8;
let addr = state.allocate(num_bits);
state.write(&addr, state.zero(num_bits as u32))?;
Ok(addr)
}
pub fn realloc<B: Backend>(
state: &mut State<B>,
addr: &Operand,
num_bytes: &Operand,
) -> Result<B::BV> {
let addr = state.operand_to_bv(addr)?;
let new_size = try_as_u64(num_bytes).unwrap_or(MAX_ALLOCATION_SIZE_BYTES);
if new_size > MAX_ALLOCATION_SIZE_BYTES {
warn!("warning: encountered an allocation of {} bytes, greater than the assumed max of {}. \
Since this allocation is constant-sized, it's fine in this case, but does draw into question the assumption.", new_size, MAX_ALLOCATION_SIZE_BYTES);
}
let old_size = state.get_allocation_size(&addr)?.ok_or_else(|| {
Error::OtherError("realloc: failed to get old allocation size".to_owned())
})?;
if new_size <= old_size {
Ok(addr)
} else {
let new_addr = state.allocate(new_size);
let contents = state.read(&addr, old_size as u32)?;
state.write(&new_addr, contents)?;
Ok(new_addr)
}
}
fn try_as_u64(op: &Operand) -> Option<u64> {
match op {
Operand::ConstantOperand(cref) => match cref.as_ref() {
Constant::Int { value, .. } => Some(*value),
_ => None,
},
_ => None,
}
}