diff --git a/repos/base/run/slab.run b/repos/base/run/slab.run index 5332fa7938..a435032270 100644 --- a/repos/base/run/slab.run +++ b/repos/base/run/slab.run @@ -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 diff --git a/repos/base/src/lib/base/slab.cc b/repos/base/src/lib/base/slab.cc index 8ed6e0d826..22094a6a06 100644 --- a/repos/base/src/lib/base/slab.cc +++ b/repos/base/src/lib/base/slab.cc @@ -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,8 +322,8 @@ 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 ", - _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)&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++; diff --git a/repos/base/src/test/slab/main.cc b/repos/base/src/test/slab/main.cc index f9c8aa84e8..2e92673648 100644 --- a/repos/base/src/test/slab/main.cc +++ b/repos/base/src/test/slab/main.cc @@ -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"); } diff --git a/tool/autopilot.list b/tool/autopilot.list index 4e928eb5eb..62f45ea846 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -90,3 +90,4 @@ trace input_filter init nic_dump +slab