slab: detect corrupted slab and invalid frees

and report about that.

Fixes #2350
This commit is contained in:
Alexander Boettcher 2017-03-23 23:20:35 +01:00 committed by Christian Helmuth
parent 62c59a56d1
commit 1c79ba4182
4 changed files with 49 additions and 11 deletions

View File

@ -1,3 +1,8 @@
if {[get_cmd_switch --autopilot] && [have_include "power_on/qemu"]} {
puts "\nRunning slab benchmark in autopilot on Qemu is not recommended.\n"
exit
}
build "core init drivers/timer test/slab"
create_boot_directory

View File

@ -23,6 +23,8 @@ using namespace Genode;
*/
class Genode::Slab::Block
{
friend struct Genode::Slab::Entry;
public:
Block *next = this; /* next block in ring */
@ -71,6 +73,12 @@ class Genode::Slab::Block
*/
int _slab_entry_idx(Entry *e);
/**
* These functions are called by Slab::Entry.
*/
void inc_avail(Entry &e);
void dec_avail() { _avail--; }
public:
/**
@ -96,12 +104,6 @@ class Genode::Slab::Block
* Return a used slab block entry
*/
Entry *any_used_entry();
/**
* These functions are called by Slab::Entry.
*/
void inc_avail(Entry &e);
void dec_avail() { _avail--; }
};
@ -124,6 +126,9 @@ struct Genode::Slab::Entry
block.inc_avail(*this);
}
bool used() {
return block._state(block._slab_entry_idx(this)) == Block::USED; }
/**
* Lookup Entry by given address
*
@ -317,7 +322,7 @@ bool Slab::alloc(size_t size, void **out_addr)
/* too large for us ? */
if (size > _slab_size) {
Genode::error("requested size ", size, " is larger then slab size ",
error("requested size ", size, " is larger then slab size ",
_slab_size);
return false;
}
@ -370,8 +375,20 @@ void Slab::_free(void *addr)
if (!e)
return;
if (addr < (void *)((addr_t)&e->block + sizeof(e->block)) ||
addr >= (void *)((addr_t)&e->block + _block_size)) {
error("slab block ", Hex_range<addr_t>((addr_t)&e->block, _block_size),
" is corrupt - slab address ", addr);
return;
}
Block &block = e->block;
if (!e->used()) {
error("slab address ", addr, " freed which is unused");
return;
}
e->~Entry();
_total_avail++;

View File

@ -2,7 +2,6 @@
* \brief Slab allocator test
* \author Norman Feske
* \date 2015-03-31
*
*/
/*
@ -65,7 +64,7 @@ struct Array_of_slab_elements
void Component::construct(Genode::Env & env)
{
Genode::Heap heap(env.ram(), env.rm());
static Genode::Heap heap(env.ram(), env.rm());
log("--- slab test ---");
@ -94,7 +93,7 @@ void Component::construct(Genode::Env & env)
* take the overhead of the two block allocations at the heap into
* account.
*/
enum { HEAP_OVERHEAD = 36 };
enum { HEAP_OVERHEAD = 9*sizeof(long) };
if (alloc.consumed() > 2*(BLOCK_SIZE + HEAP_OVERHEAD)) {
error("slab failed to release empty slab blocks");
return;
@ -108,5 +107,21 @@ void Component::construct(Genode::Env & env)
return;
}
{
log("test double-free detection - error message is expected");
Genode::Slab slab(SLAB_SIZE, BLOCK_SIZE, nullptr, &alloc);
void *p = nullptr;
{
Array_of_slab_elements array(slab, 4096, SLAB_SIZE, heap);
p = array.elem[1705];
}
slab.free(p, SLAB_SIZE);
{
Array_of_slab_elements array(slab, 4096, SLAB_SIZE, heap);
}
}
log("Test done");
}

View File

@ -90,3 +90,4 @@ trace
input_filter
init
nic_dump
slab