Skip to content

Commit

Permalink
Add better stream output to overflow allocator
Browse files Browse the repository at this point in the history
Update README
  • Loading branch information
KredeGC committed Mar 29, 2023
1 parent 0897420 commit 392c83a
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: Docs

on:
push:
branches: [ master ]
paths: '**/*.md'
workflow_dispatch:

jobs:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
paths-ignore:
- '**/*.md'
- '**/*.gitignore'
- '**/Doxyfile'

jobs:
Build:
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ This library also contains various containers that are STL compliant.
| `size_t size() const` | Returns the current amount of elements in the vector. |

# Allocator Examples
The following examples all have `using namespace ktl` or equivalent at the top for brevity.
These examples can all be seen as unit tests in [`src/test/exotic_allocator_test.cpp`](https://github.com/KredeGC/KTL/tree/master/src/test/exotic_allocator_test.cpp).

Create an allocator which will attempt to use a linear allocator for allocation, but fall back on malloc when full.
```cpp
// Create the allocator from some 8kb buffer and straight malloc
Expand Down
83 changes: 75 additions & 8 deletions include/ktl/allocators/overflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ namespace ktl
typedef typename detail::get_size_type_t<Alloc> size_type;

private:
static constexpr int OVERFLOW_PATTERN = 0b01010101010101010101010101010101;
static constexpr int64_t OVERFLOW_TEST = 0b0101010101010101010101010101010101010101010101010101010101010101;
static constexpr size_t OVERFLOW_SIZE = 8;
static constexpr unsigned int OVERFLOW_PATTERN = 0b10100101101001011010010110100101;
static constexpr unsigned char OVERFLOW_TEST = 0b10100101;
static constexpr size_t OVERFLOW_SIZE = 64;

public:
/**
* @brief Construct the allocator with a reference to a stream object
* @param stream The stream to use when leaks or corruption happens
*/
explicit overflow(Stream& stream) noexcept :
m_Stream(stream),
m_Alloc(),
Expand Down Expand Up @@ -85,6 +89,13 @@ namespace ktl
}

#pragma region Allocation
/**
* @brief Attempts to allocate a chunk of memory defined by @p n
* @note Allocates 64 bytes more on either side of the returned address.
* This memory will be used for overflow checking.
* @param n The amount of bytes to allocate memory for
* @return A location in memory that is at least @p n bytes big or nullptr if it could not be allocated
*/
void* allocate(size_type n)
{
m_Allocs += n;
Expand All @@ -101,6 +112,11 @@ namespace ktl
return ptr + OVERFLOW_SIZE;
}

/**
* @brief Attempts to deallocate the memory at location @p p
* @param p The location in memory to deallocate
* @param n The size that was initially allocated
*/
void deallocate(void* p, size_type n)
{
KTL_ASSERT(p != nullptr);
Expand All @@ -109,14 +125,34 @@ namespace ktl

if (p)
{
char* ptr = reinterpret_cast<char*>(p);
unsigned char* ptr = reinterpret_cast<unsigned char*>(p);

size_t before = 0;
size_t after = 0;

// Check against corruption
if (std::memcmp(ptr + n, &OVERFLOW_TEST, OVERFLOW_SIZE) != 0)
m_Stream << "--------MEMORY CORRUPTION DETECTED--------\nThe area around " << reinterpret_cast<int*>(ptr + n) << " has been illegally modified\n";
for (unsigned char* i = ptr - 1; i >= ptr - OVERFLOW_SIZE; i--)
{
if (*i != OVERFLOW_TEST)
before = ptr - i;
}

for (unsigned char* i = ptr + n; i < ptr + n + OVERFLOW_SIZE; i++)
{
if (*i != OVERFLOW_TEST)
after = i - ptr - n + 1;
}

if (before || after)
{
m_Stream << "--------MEMORY CORRUPTION DETECTED--------\nThe area around " << p << " (" << n << " bytes) has been illegally modified\n";

if (std::memcmp(ptr - OVERFLOW_SIZE, &OVERFLOW_TEST, OVERFLOW_SIZE) != 0)
m_Stream << "--------MEMORY CORRUPTION DETECTED--------\nThe area around " << reinterpret_cast<int*>(ptr - OVERFLOW_SIZE) << " has been illegally modified\n";
if (before)
m_Stream << " Before (" << before << " bytes)\n";

if (after)
m_Stream << " After (" << after << " bytes)\n";
}

size_type size = n + OVERFLOW_SIZE * 2;
m_Alloc.deallocate(ptr - OVERFLOW_SIZE, size);
Expand All @@ -125,6 +161,13 @@ namespace ktl
#pragma endregion

#pragma region Construction
/**
* @brief Constructs an object of T with the given @p ...args at the given location
* @note Keeps track of the number of constructions
* @tparam ...Args The types of the arguments
* @param p The location of the object in memory
* @param ...args A range of arguments to use to construct the object
*/
template<typename T, typename... Args>
void construct(T* p, Args&&... args)
{
Expand All @@ -136,6 +179,11 @@ namespace ktl
::new(p) T(std::forward<Args>(args)...);
}

/**
* @brief Destructs an object of T at the given location
* @note Keeps track of the number of destructions
* @param p The location of the object in memory
*/
template<typename T>
void destroy(T* p)
{
Expand All @@ -149,13 +197,24 @@ namespace ktl
#pragma endregion

#pragma region Utility
/**
* @brief Returns the maximum size that an allocation can be
* @note Only defined if the underlying allocator defines it
* @return The maximum size an allocation may be
*/
template<typename A = Alloc>
typename std::enable_if<detail::has_max_size_v<A>, size_type>::type
max_size() const noexcept
{
return m_Alloc.max_size();
}

/**
* @brief Returns whether or not the allocator owns the given location in memory
* @note Only defined if the underlying allocator defines it
* @param p The location of the object in memory
* @return Whether the allocator owns @p p
*/
template<typename A = Alloc>
typename std::enable_if<detail::has_owns_v<A>, bool>::type
owns(void* p) const
Expand All @@ -164,11 +223,19 @@ namespace ktl
}
#pragma endregion

/**
* @brief Returns a reference to the underlying allocator
* @return The allocator
*/
Alloc& get_allocator()
{
return m_Alloc;
}

/**
* @brief Returns a const reference to the underlying allocator
* @return The allocator
*/
const Alloc& get_allocator() const
{
return m_Alloc;
Expand Down

0 comments on commit 392c83a

Please sign in to comment.