Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibJS/Heap/HeapBlock.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2020-2024, Andreas Kling <andreas@ladybird.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <AK/Assertions.h>
8
#include <AK/NonnullOwnPtr.h>
9
#include <AK/Platform.h>
10
#include <LibJS/Heap/Heap.h>
11
#include <LibJS/Heap/HeapBlock.h>
12
#include <stdio.h>
13
#include <sys/mman.h>
14
15
#ifdef HAS_ADDRESS_SANITIZER
16
#    include <sanitizer/asan_interface.h>
17
#endif
18
19
namespace JS {
20
21
size_t HeapBlockBase::block_size = PAGE_SIZE;
22
23
NonnullOwnPtr<HeapBlock> HeapBlock::create_with_cell_size(Heap& heap, CellAllocator& cell_allocator, size_t cell_size, [[maybe_unused]] char const* class_name)
24
0
{
25
#ifdef AK_OS_SERENITY
26
    char name[64];
27
    if (class_name)
28
        snprintf(name, sizeof(name), "LibJS: HeapBlock(%zu): %s", cell_size, class_name);
29
    else
30
        snprintf(name, sizeof(name), "LibJS: HeapBlock(%zu)", cell_size);
31
#else
32
0
    char const* name = nullptr;
33
0
#endif
34
0
    auto* block = static_cast<HeapBlock*>(cell_allocator.block_allocator().allocate_block(name));
35
0
    new (block) HeapBlock(heap, cell_allocator, cell_size);
36
0
    return NonnullOwnPtr<HeapBlock>(NonnullOwnPtr<HeapBlock>::Adopt, *block);
37
0
}
38
39
HeapBlock::HeapBlock(Heap& heap, CellAllocator& cell_allocator, size_t cell_size)
40
0
    : HeapBlockBase(heap)
41
0
    , m_cell_allocator(cell_allocator)
42
0
    , m_cell_size(cell_size)
43
0
{
44
0
    VERIFY(cell_size >= sizeof(FreelistEntry));
45
0
    ASAN_POISON_MEMORY_REGION(m_storage, block_size - sizeof(HeapBlock));
46
0
}
47
48
void HeapBlock::deallocate(Cell* cell)
49
0
{
50
0
    VERIFY(is_valid_cell_pointer(cell));
51
0
    VERIFY(!m_freelist || is_valid_cell_pointer(m_freelist));
52
0
    VERIFY(cell->state() == Cell::State::Live);
53
0
    VERIFY(!cell->is_marked());
54
55
0
    cell->~Cell();
56
0
    auto* freelist_entry = new (cell) FreelistEntry();
57
0
    freelist_entry->set_state(Cell::State::Dead);
58
0
    freelist_entry->next = m_freelist;
59
0
    m_freelist = freelist_entry;
60
61
#ifdef HAS_ADDRESS_SANITIZER
62
    auto dword_after_freelist = round_up_to_power_of_two(reinterpret_cast<uintptr_t>(freelist_entry) + sizeof(FreelistEntry), 8);
63
    VERIFY((dword_after_freelist - reinterpret_cast<uintptr_t>(freelist_entry)) <= m_cell_size);
64
    VERIFY(m_cell_size >= sizeof(FreelistEntry));
65
    // We can't poision the cell tracking data, nor the FreeListEntry's vtable or next pointer
66
    // This means there's sizeof(FreelistEntry) data at the front of each cell that is always read/write
67
    // On x86_64, this ends up being 24 bytes due to the size of the FreeListEntry's vtable, while on x86, it's only 12 bytes.
68
    ASAN_POISON_MEMORY_REGION(reinterpret_cast<void*>(dword_after_freelist), m_cell_size - sizeof(FreelistEntry));
69
#endif
70
0
}
71
72
}