/ externals / biscuit / src / code_buffer.cpp
code_buffer.cpp
  1  #include <biscuit/assert.hpp>
  2  #include <biscuit/code_buffer.hpp>
  3  
  4  #include <cstring>
  5  #include <utility>
  6  
  7  #ifdef BISCUIT_CODE_BUFFER_MMAP
  8  #include <sys/mman.h>
  9  #endif
 10  
 11  namespace biscuit {
 12  
 13  CodeBuffer::CodeBuffer(size_t capacity)
 14      : m_capacity{capacity}, m_is_managed{true} {
 15      if (capacity == 0) {
 16          return;
 17      }
 18  
 19  #ifdef BISCUIT_CODE_BUFFER_MMAP
 20      m_buffer = static_cast<uint8_t*>(mmap(nullptr, capacity,
 21                                            PROT_READ | PROT_WRITE,
 22                                            MAP_PRIVATE | MAP_ANONYMOUS,
 23                                            -1, 0));
 24      BISCUIT_ASSERT(m_buffer != nullptr);
 25  #else
 26      m_buffer = new uint8_t[capacity]();
 27  #endif
 28  
 29      m_cursor = m_buffer;
 30  }
 31  
 32  CodeBuffer::CodeBuffer(uint8_t* buffer, size_t capacity)
 33      : m_buffer{buffer}, m_cursor{buffer}, m_capacity{capacity} {
 34      BISCUIT_ASSERT(buffer != nullptr);
 35  }
 36  
 37  CodeBuffer::CodeBuffer(CodeBuffer&& other) noexcept
 38      : m_buffer{std::exchange(other.m_buffer, nullptr)}
 39      , m_cursor{std::exchange(other.m_cursor, nullptr)}
 40      , m_capacity{std::exchange(other.m_capacity, size_t{0})}
 41      , m_is_managed{std::exchange(other.m_is_managed, false)} {}
 42  
 43  CodeBuffer& CodeBuffer::operator=(CodeBuffer&& other) noexcept {
 44      if (this == &other) {
 45          return *this;
 46      }
 47  
 48      std::swap(m_buffer, other.m_buffer);
 49      std::swap(m_cursor, other.m_cursor);
 50      std::swap(m_capacity, other.m_capacity);
 51      std::swap(m_is_managed, other.m_is_managed);
 52      return *this;
 53  }
 54  
 55  CodeBuffer::~CodeBuffer() noexcept {
 56      if (!m_is_managed) {
 57          return;
 58      }
 59  
 60  #ifdef BISCUIT_CODE_BUFFER_MMAP
 61      munmap(m_buffer, m_capacity);
 62  #else
 63      delete[] m_buffer;
 64  #endif
 65  }
 66  
 67  void CodeBuffer::Grow(size_t new_capacity) {
 68      BISCUIT_ASSERT(IsManaged());
 69  
 70      // No-op, just return.
 71      if (new_capacity <= m_capacity) {
 72          return;
 73      }
 74  
 75      const auto cursor_offset = GetCursorOffset();
 76  
 77  #ifdef BISCUIT_CODE_BUFFER_MMAP
 78      auto* new_buffer = static_cast<uint8_t*>(mremap(m_buffer, m_capacity, new_capacity, MREMAP_MAYMOVE));
 79      BISCUIT_ASSERT(new_buffer != nullptr);
 80  #else
 81      auto* new_buffer = new uint8_t[new_capacity]();
 82      std::memcpy(new_buffer, m_buffer, m_capacity);
 83      delete[] m_buffer;
 84  #endif
 85  
 86      m_buffer = new_buffer;
 87      m_capacity = new_capacity;
 88      m_cursor = m_buffer + cursor_offset;
 89  }
 90  
 91  void CodeBuffer::SetExecutable() {
 92  #ifdef BISCUIT_CODE_BUFFER_MMAP
 93      const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_EXEC);
 94      BISCUIT_ASSERT(result == 0);
 95  #else
 96      // Unimplemented/Unnecessary for new
 97      BISCUIT_ASSERT(false);
 98  #endif
 99  }
100  
101  void CodeBuffer::SetWritable() {
102  #ifdef BISCUIT_CODE_BUFFER_MMAP
103      const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_WRITE);
104      BISCUIT_ASSERT(result == 0);
105  #else
106      // Unimplemented/Unnecessary for new
107      BISCUIT_ASSERT(false);
108  #endif
109  }
110  
111  } // namespace biscuit