allocator_avl: use Attempt for size_at

Fixes ambiguous interpretation of returned 0.

genodelabs/genode#4393
This commit is contained in:
Johannes Schlatow 2022-01-31 15:51:11 +01:00 committed by Norman Feske
parent 5aa0fea29b
commit db3a647c6d
10 changed files with 86 additions and 24 deletions

View File

@ -104,8 +104,14 @@ namespace Genode {
* Determine size of a core local mapping required for a
* core_rm_session detach().
*/
size_t region_alloc_size_at(void * addr) {
return (_core_mem_alloc.virt_alloc())()->size_at(addr); }
size_t region_alloc_size_at(void * addr)
{
using Size_at_error = Allocator_avl::Size_at_error;
return (_core_mem_alloc.virt_alloc())()->size_at(addr).convert<size_t>(
[ ] (size_t s) { return s; },
[ ] (Size_at_error) { return 0U; });
}
/**
* Return kernel CPU ID for given Genode CPU

View File

@ -276,8 +276,14 @@ class Genode::Platform : public Platform_generic
* Determine size of a core local mapping required for a
* core_rm_session detach().
*/
size_t region_alloc_size_at(void * addr) {
return (_core_mem_alloc.virt_alloc())()->size_at(addr); }
size_t region_alloc_size_at(void * addr)
{
using Size_at_error = Allocator_avl::Size_at_error;
return (_core_mem_alloc.virt_alloc())()->size_at(addr).convert<size_t>(
[ ] (size_t s) { return s; },
[ ] (Size_at_error) { return 0U; });
}
size_t max_caps() const override
{

View File

@ -45,6 +45,15 @@ namespace Genode {
class Genode::Allocator_avl_base : public Range_allocator
{
public:
enum class Size_at_error {
UNKNOWN_ADDR, /* no allocation at specified address */
MISMATCHING_ADDR, /* specified address is not the start of a block */
};
using Size_at_result = Attempt<size_t, Size_at_error>;
private:
static bool _sum_in_range(addr_t addr, addr_t offset) {
@ -287,7 +296,7 @@ class Genode::Allocator_avl_base : public Range_allocator
/**
* Return size of block at specified address
*/
size_t size_at(void const *addr) const;
Size_at_result size_at(void const *addr) const;
/**
* Return the memory overhead per Block

View File

@ -394,15 +394,18 @@ void Allocator_avl_base::free(void *addr)
}
size_t Allocator_avl_base::size_at(void const *addr) const
Allocator_avl_base::Size_at_result Allocator_avl_base::size_at(void const *addr) const
{
/* lookup corresponding block */
Block *b = _find_by_address(reinterpret_cast<addr_t>(addr));
if (b && (b->addr() != (addr_t)addr))
return 0;
return Size_at_error::MISMATCHING_ADDR;
return (b && b->used()) ? b->size() : 0;
if (b && b->used())
return b->size();
return Size_at_error::UNKNOWN_ADDR;
}

View File

@ -255,14 +255,27 @@ void Heap::free(void *addr, size_t)
/* serialize access of heap functions */
Mutex::Guard guard(_mutex);
/* try to find the size in our local allocator */
size_t const size = _alloc->size_at(addr);
using Size_at_error = Allocator_avl::Size_at_error;
if (size != 0) {
Allocator_avl::Size_at_result size_at_result = _alloc->size_at(addr);
if (size_at_result.ok()) {
/* forward request to our local allocator */
_alloc->free(addr, size);
_quota_used -= size;
size_at_result.with_result(
[&] (size_t size) {
/* forward request to our local allocator */
_alloc->free(addr, size);
_quota_used -= size;
},
[&] (Size_at_error) { });
return;
}
if (size_at_result == Size_at_error::MISMATCHING_ADDR) {
/* address was found in local allocator but is not a block start address */
error("heap could not free memory block: given address ", addr,
" is not a block start adress");
return;
}
@ -278,7 +291,7 @@ void Heap::free(void *addr, size_t)
break;
if (!ds) {
warning("heap could not free memory block");
warning("heap could not free memory block: invalid address");
return;
}

View File

@ -173,17 +173,24 @@ bool Lx_kit::Mem_allocator::free(const void * ptr)
if (!_mem.valid_addr((addr_t)ptr))
return false;
if (!_mem.size_at(ptr))
return true;
using Size_at_error = Allocator_avl::Size_at_error;
_mem.size_at(ptr).with_result(
[&] (size_t) { _mem.free(const_cast<void*>(ptr)); },
[ ] (Size_at_error) { });
_mem.free(const_cast<void*>(ptr));
return true;
}
Genode::size_t Lx_kit::Mem_allocator::size(const void * ptr)
{
return ptr ? _mem.size_at(ptr) : 0;
if (!ptr) return 0;
using Size_at_error = Allocator_avl::Size_at_error;
return _mem.size_at(ptr).convert<size_t>([ ] (size_t s) { return s; },
[ ] (Size_at_error) { return 0U; });
}

View File

@ -28,9 +28,12 @@ namespace Libc {
struct Mem_alloc
{
using Size_at_error = Allocator_avl::Size_at_error;
using Size_at_result = Allocator_avl::Size_at_result;
virtual void *alloc(size_t size, size_t align_log2) = 0;
virtual void free(void *ptr) = 0;
virtual size_t size_at(void const *ptr) const = 0;
virtual Size_at_result size_at(void const *ptr) const = 0;
};
/**
@ -124,7 +127,7 @@ namespace Libc {
void *alloc(size_t size, size_t align_log2);
void free(void *ptr);
size_t size_at(void const *ptr) const;
Size_at_result size_at(void const *ptr) const;
};
}

View File

@ -143,7 +143,7 @@ void Libc::Mem_alloc_impl::free(void *addr)
}
size_t Libc::Mem_alloc_impl::size_at(void const *addr) const
Libc::Mem_alloc::Size_at_result Libc::Mem_alloc_impl::size_at(void const *addr) const
{
/* serialize access of heap functions */
Mutex::Guard guard(_mutex);

View File

@ -2429,12 +2429,23 @@ void *Libc::Vfs_plugin::mmap(void *addr_in, ::size_t length, int prot, int flags
int Libc::Vfs_plugin::munmap(void *addr, ::size_t)
{
if (mem_alloc()->size_at(addr) > 0) {
using Size_at_error = Mem_alloc::Size_at_error;
Mem_alloc::Size_at_result const size_at_result = mem_alloc()->size_at(addr);
if (size_at_result.ok()) {
/* private mapping */
mem_alloc()->free(addr);
size_at_result.with_result(
[&] (size_t) { mem_alloc()->free(addr); },
[&] (Size_at_error) { });
return 0;
}
/* return error if addr is not a block start address */
if (size_at_result == Size_at_error::MISMATCHING_ADDR)
return Errno(EINVAL);
/* shared mapping */
Vfs::Vfs_handle *reference_handle = nullptr;

View File

@ -109,8 +109,12 @@ extern "C" void *realloc(void *ptr, ::size_t size)
unsigned long old_size = size;
if (!initial_memory(ptr)) {
using Size_at_error = Libc::Mem_alloc::Size_at_error;
/* determine size of old block content (without header) */
old_size = memory()->size_at(ptr);
old_size = memory()->size_at(ptr).convert<size_t>(
[ ] (size_t s) { return s; },
[ ] (Size_at_error) { return 0U; });
/* do not reallocate if new size is less than the current size */
if (size <= old_size)