vm-allocator: Fix potential allocation errors

There is one corner case which was not properly handled by the current
code from our AddressAllocator. If both the address start (from the
next range) and the requested region size are already aligned on the
same value as "alignment", when doing the substract of the requested
size + alignment, the returned address is already aligned. The problem
is that we might end up overlapping with an existing range since the
check between the available delta and the requested size does not take
into account a full extra alignment.

By substracting the requested size + alignment - 1 from the address
start of the next range, we ensure this kind of corner case would not
happen since the address won't be naturally aligned and after some
adjustment from the function align_address(), the correct start address
will be returned.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-07-24 14:34:10 -07:00 committed by Rob Bradford
parent 927861ced2
commit 0ff074d2b8
2 changed files with 8 additions and 7 deletions

View File

@ -30,7 +30,7 @@ pub type Result<T> = result::Result<T, Error>;
/// # use vm_memory::{Address, GuestAddress, GuestUsize};
/// AddressAllocator::new(GuestAddress(0x1000), 0x10000).map(|mut pool| {
/// assert_eq!(pool.allocate(None, 0x110, Some(0x100)), Some(GuestAddress(0x10e00)));
/// assert_eq!(pool.allocate(None, 0x100, Some(0x100)), Some(GuestAddress(0x10c00)));
/// assert_eq!(pool.allocate(None, 0x100, Some(0x100)), Some(GuestAddress(0x10d00)));
/// });
/// ```
#[derive(Debug, Eq, PartialEq)]
@ -147,9 +147,10 @@ impl AddressAllocator {
if let Some(size_delta) =
address.checked_sub(self.align_address(prev_end_address, alignment).raw_value())
{
let adjust = if alignment > 1 { alignment - 1 } else { 0 };
if size_delta.raw_value() >= req_size {
return Some(
self.align_address(address.unchecked_sub(req_size + alignment), alignment),
self.align_address(address.unchecked_sub(req_size + adjust), alignment),
);
}
}
@ -242,12 +243,12 @@ mod tests {
let mut pool = AddressAllocator::new(GuestAddress(0x1000), 0x1000).unwrap();
assert_eq!(
pool.allocate(None, 0x800, Some(0x100)),
Some(GuestAddress(0x1700))
Some(GuestAddress(0x1800))
);
assert_eq!(pool.allocate(None, 0x900, Some(0x100)), None);
assert_eq!(
pool.allocate(None, 0x400, Some(0x100)),
Some(GuestAddress(0x1200))
Some(GuestAddress(0x1400))
);
}
@ -260,11 +261,11 @@ mod tests {
);
assert_eq!(
pool.allocate(None, 0x100, Some(0x100)),
Some(GuestAddress(0x10c00))
Some(GuestAddress(0x10d00))
);
assert_eq!(
pool.allocate(None, 0x10, Some(0x100)),
Some(GuestAddress(0x10d00))
Some(GuestAddress(0x10c00))
);
}

View File

@ -35,7 +35,7 @@ fn pagesize() -> usize {
/// vec![GsiApic::new(5, 19)]).unwrap();
/// assert_eq!(allocator.allocate_irq(), Some(5));
/// assert_eq!(allocator.allocate_irq(), Some(6));
/// assert_eq!(allocator.allocate_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fffe000)));
/// assert_eq!(allocator.allocate_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
///
/// ```
pub struct SystemAllocator {