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

@@ -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;
}