mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 02:47:34 +00:00
LibJS: Fix undefined behavior in HeapBlock
In C++, it's invalid to cast a block of memory to a complex type without invoking its constructor. It's even more invalid to simply cast a pointer to a block of memory to a pointer to *an abstract type*. To fix this, make sure FreelistEntry is a concrete type, and call its constructor whenever appropriate.
This commit is contained in:
parent
53a94b8bbd
commit
2fbc37befc
2 changed files with 23 additions and 12 deletions
|
@ -61,15 +61,16 @@ HeapBlock::HeapBlock(Heap& heap, size_t cell_size)
|
||||||
: m_heap(heap)
|
: m_heap(heap)
|
||||||
, m_cell_size(cell_size)
|
, m_cell_size(cell_size)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < cell_count(); ++i) {
|
ASSERT(cell_size >= sizeof(FreelistEntry));
|
||||||
auto* freelist_entry = static_cast<FreelistEntry*>(cell(i));
|
|
||||||
|
FreelistEntry* next = nullptr;
|
||||||
|
for (ssize_t i = cell_count() - 1; i >= 0; i--) {
|
||||||
|
auto* freelist_entry = init_freelist_entry(i);
|
||||||
freelist_entry->set_live(false);
|
freelist_entry->set_live(false);
|
||||||
if (i == cell_count() - 1)
|
freelist_entry->next = next;
|
||||||
freelist_entry->next = nullptr;
|
next = freelist_entry;
|
||||||
else
|
|
||||||
freelist_entry->next = static_cast<FreelistEntry*>(cell(i + 1));
|
|
||||||
}
|
}
|
||||||
m_freelist = static_cast<FreelistEntry*>(cell(0));
|
m_freelist = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell* HeapBlock::allocate()
|
Cell* HeapBlock::allocate()
|
||||||
|
@ -84,7 +85,7 @@ void HeapBlock::deallocate(Cell* cell)
|
||||||
ASSERT(cell->is_live());
|
ASSERT(cell->is_live());
|
||||||
ASSERT(!cell->is_marked());
|
ASSERT(!cell->is_marked());
|
||||||
cell->~Cell();
|
cell->~Cell();
|
||||||
auto* freelist_entry = static_cast<FreelistEntry*>(cell);
|
auto* freelist_entry = new (cell) FreelistEntry();
|
||||||
freelist_entry->set_live(false);
|
freelist_entry->set_live(false);
|
||||||
freelist_entry->next = m_freelist;
|
freelist_entry->next = m_freelist;
|
||||||
m_freelist = freelist_entry;
|
m_freelist = freelist_entry;
|
||||||
|
|
|
@ -42,8 +42,6 @@ public:
|
||||||
size_t cell_size() const { return m_cell_size; }
|
size_t cell_size() const { return m_cell_size; }
|
||||||
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
size_t cell_count() const { return (block_size - sizeof(HeapBlock)) / m_cell_size; }
|
||||||
|
|
||||||
Cell* cell(size_t index) { return reinterpret_cast<Cell*>(&m_storage[index * cell_size()]); }
|
|
||||||
|
|
||||||
Cell* allocate();
|
Cell* allocate();
|
||||||
void deallocate(Cell*);
|
void deallocate(Cell*);
|
||||||
|
|
||||||
|
@ -72,10 +70,22 @@ public:
|
||||||
private:
|
private:
|
||||||
HeapBlock(Heap&, size_t cell_size);
|
HeapBlock(Heap&, size_t cell_size);
|
||||||
|
|
||||||
struct FreelistEntry : public Cell {
|
struct FreelistEntry final : public Cell {
|
||||||
FreelistEntry* next;
|
FreelistEntry* next { nullptr };
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "FreelistEntry"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Cell* cell(size_t index)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Cell*>(&m_storage[index * cell_size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreelistEntry* init_freelist_entry(size_t index)
|
||||||
|
{
|
||||||
|
return new (&m_storage[index * cell_size()]) FreelistEntry();
|
||||||
|
}
|
||||||
|
|
||||||
Heap& m_heap;
|
Heap& m_heap;
|
||||||
size_t m_cell_size { 0 };
|
size_t m_cell_size { 0 };
|
||||||
FreelistEntry* m_freelist { nullptr };
|
FreelistEntry* m_freelist { nullptr };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue