aboutsummaryrefslogtreecommitdiffhomepage
path: root/externals/biscuit/src/code_buffer.cpp
blob: 386be3757bcc41ef716a7ee503bc98fca0b9f18c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <biscuit/assert.hpp>
#include <biscuit/code_buffer.hpp>

#include <cstring>
#include <utility>

#ifdef BISCUIT_CODE_BUFFER_MMAP
#include <sys/mman.h>
#endif

namespace biscuit {

CodeBuffer::CodeBuffer(size_t capacity)
    : m_capacity{capacity}, m_is_managed{true} {
    if (capacity == 0) {
        return;
    }

#ifdef BISCUIT_CODE_BUFFER_MMAP
    m_buffer = static_cast<uint8_t*>(mmap(nullptr, capacity,
                                          PROT_READ | PROT_WRITE,
                                          MAP_PRIVATE | MAP_ANONYMOUS,
                                          -1, 0));
    BISCUIT_ASSERT(m_buffer != nullptr);
#else
    m_buffer = new uint8_t[capacity]();
#endif

    m_cursor = m_buffer;
}

CodeBuffer::CodeBuffer(uint8_t* buffer, size_t capacity)
    : m_buffer{buffer}, m_cursor{buffer}, m_capacity{capacity} {
    BISCUIT_ASSERT(buffer != nullptr);
}

CodeBuffer::CodeBuffer(CodeBuffer&& other) noexcept
    : m_buffer{std::exchange(other.m_buffer, nullptr)}
    , m_cursor{std::exchange(other.m_cursor, nullptr)}
    , m_capacity{std::exchange(other.m_capacity, size_t{0})}
    , m_is_managed{std::exchange(other.m_is_managed, false)} {}

CodeBuffer& CodeBuffer::operator=(CodeBuffer&& other) noexcept {
    if (this == &other) {
        return *this;
    }

    std::swap(m_buffer, other.m_buffer);
    std::swap(m_cursor, other.m_cursor);
    std::swap(m_capacity, other.m_capacity);
    std::swap(m_is_managed, other.m_is_managed);
    return *this;
}

CodeBuffer::~CodeBuffer() noexcept {
    if (!m_is_managed) {
        return;
    }

#ifdef BISCUIT_CODE_BUFFER_MMAP
    munmap(m_buffer, m_capacity);
#else
    delete[] m_buffer;
#endif
}

void CodeBuffer::Grow(size_t new_capacity) {
    BISCUIT_ASSERT(IsManaged());

    // No-op, just return.
    if (new_capacity <= m_capacity) {
        return;
    }

    const auto cursor_offset = GetCursorOffset();

#ifdef BISCUIT_CODE_BUFFER_MMAP
    auto* new_buffer = static_cast<uint8_t*>(mremap(m_buffer, m_capacity, new_capacity, MREMAP_MAYMOVE));
    BISCUIT_ASSERT(new_buffer != nullptr);
#else
    auto* new_buffer = new uint8_t[new_capacity]();
    std::memcpy(new_buffer, m_buffer, m_capacity);
    delete[] m_buffer;
#endif

    m_buffer = new_buffer;
    m_capacity = new_capacity;
    m_cursor = m_buffer + cursor_offset;
}

void CodeBuffer::SetExecutable() {
#ifdef BISCUIT_CODE_BUFFER_MMAP
    const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_EXEC);
    BISCUIT_ASSERT(result == 0);
#else
    // Unimplemented/Unnecessary for new
    BISCUIT_ASSERT(false);
#endif
}

void CodeBuffer::SetWritable() {
#ifdef BISCUIT_CODE_BUFFER_MMAP
    const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_WRITE);
    BISCUIT_ASSERT(result == 0);
#else
    // Unimplemented/Unnecessary for new
    BISCUIT_ASSERT(false);
#endif
}

} // namespace biscuit