Skip to content

Commit 547cf23

Browse files
authored
Add magic number and canary checks to malloc and free implementation (#39)
## Description Add magic number and canary checks to malloc and free implementation. ## Issues <!-- use if this PR fully resolves the issue --> Closes #37 <!-- use if this PR is linked but should not close the issue --> Related: #<issue-number> ## Testing <!-- Steps or notes on how reviewers can verify. -->
1 parent 247c2b3 commit 547cf23

File tree

3 files changed

+61
-13
lines changed

3 files changed

+61
-13
lines changed

include/malloc_from_scratch/memory_internal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace internal
1111

1212
struct MemoryBlock
1313
{
14+
size_t magic_;
1415
size_t size_;
1516
bool allocated_;
1617
MemoryBlock* next_;
@@ -22,20 +23,24 @@ inline size_t total_memory_allocated = 0;
2223
inline pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
2324

2425
constexpr size_t BLOCK_METADATA_SIZE = sizeof(MemoryBlock);
25-
constexpr size_t BLOCK_SIZE = 16;
2626
constexpr size_t CHUNK_SIZE = 65536;
27+
constexpr size_t MAGIC_NUMBER = 0xDEADBEEF;
28+
constexpr size_t CANARY_VALUE = 0xC0FFEE00;
29+
constexpr size_t CANARY_SIZE = sizeof(size_t);
2730

2831
// malloc
2932
void* increaseHeap(size_t size);
3033
MemoryBlock* findLargeEnoughFreeMemoryBlock(MemoryBlock** block_list_head, size_t size);
3134
void* splitFreeMemoryBlockIfPossible(MemoryBlock* new_block, size_t size);
3235
void* getMemoryBlockSplitAddress(MemoryBlock* new_block, size_t size);
3336
void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_block);
37+
void setCanary(MemoryBlock* block);
3438

3539
// free
3640
void decreaseHeap(MemoryBlock* block_heap_end);
3741
void mergeFreeMemoryBlocks();
3842
void getLastMemoryBlock(MemoryBlock** block_list_tail, MemoryBlock** block_previous_from_last);
43+
bool isBlockCorrupted(MemoryBlock* block);
3944

4045
// helpers
4146
void* getPayloadAddress(MemoryBlock* block);
@@ -44,6 +49,8 @@ MemoryBlock* getMemoryBlockFromAddress(void* address);
4449
size_t getSizeOfAllocatedMemoryBlock(MemoryBlock* block);
4550
bool isPointerInHeap(void* ptr);
4651
void* getErrorCodeInVoidPtr(size_t error_code);
52+
bool isValidBlock(MemoryBlock* block);
53+
bool checkCanary(MemoryBlock* block);
4754

4855
// Test helper functions to inspect allocator state
4956
inline size_t getTotalUsedMemory() { return total_memory_allocated; }

src/free.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,20 @@ void free(void* ptr)
2020
}
2121

2222
internal::MemoryBlock* block_to_free = internal::getMetadata(ptr);
23-
if (block_to_free == nullptr || block_to_free->allocated_ == false)
23+
if (!internal::isValidBlock(block_to_free))
2424
{
25-
if (block_to_free)
25+
if (internal::isBlockCorrupted(block_to_free))
2626
{
2727
exit(-1);
2828
}
2929
return;
3030
}
3131

32+
if (!internal::checkCanary(block_to_free))
33+
{
34+
exit(-1);
35+
}
36+
3237
internal::total_memory_allocated -= block_to_free->size_;
3338
block_to_free->allocated_ = false;
3439

@@ -91,7 +96,7 @@ void mergeFreeMemoryBlocks()
9196
{
9297
if (current->allocated_ == false && current->next_->allocated_ == false)
9398
{
94-
current->size_ += BLOCK_METADATA_SIZE + current->next_->size_;
99+
current->size_ += BLOCK_METADATA_SIZE + CANARY_SIZE + current->next_->size_;
95100
current->next_ = current->next_->next_;
96101
}
97102
else
@@ -116,5 +121,7 @@ void getLastMemoryBlock(MemoryBlock** block_list_tail, MemoryBlock** block_previ
116121
*block_previous_from_last = previous;
117122
}
118123

124+
bool isBlockCorrupted(MemoryBlock* block) { return (block && block->magic_ != MAGIC_NUMBER); }
125+
119126
} // namespace internal
120127
} // namespace mem

src/malloc.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void* malloc(size_t size)
3737
}
3838
else
3939
{
40-
total_size = internal::BLOCK_METADATA_SIZE + size;
40+
total_size = internal::BLOCK_METADATA_SIZE + size + internal::CANARY_SIZE;
4141
is_frame_used = false;
4242
}
4343

@@ -50,6 +50,7 @@ void* malloc(size_t size)
5050
internal::MemoryBlock* new_block = internal::getMemoryBlockFromAddress(new_memory_allocation);
5151
if (is_frame_used)
5252
{
53+
new_block->magic_ = internal::MAGIC_NUMBER;
5354
new_block->size_ = internal::CHUNK_SIZE;
5455
new_block->allocated_ = false;
5556
new_block->next_ = nullptr;
@@ -59,10 +60,12 @@ void* malloc(size_t size)
5960
}
6061
else
6162
{
63+
new_block->magic_ = internal::MAGIC_NUMBER;
6264
new_block->size_ = size;
6365
new_block->allocated_ = true;
6466
new_block->next_ = nullptr;
6567
internal::insertMemoryBlockAtEnd(&internal::block_list_head, new_block);
68+
internal::setCanary(new_block);
6669
internal::total_memory_allocated += size;
6770
}
6871

@@ -86,14 +89,16 @@ void* increaseHeap(size_t size)
8689
MemoryBlock* findLargeEnoughFreeMemoryBlock(MemoryBlock** block_list_head, size_t size)
8790
{
8891
MemoryBlock* current = *block_list_head;
92+
size_t size_needed = size + CANARY_SIZE;
8993
while (current != nullptr)
9094
{
91-
if (current->allocated_ == false && current->size_ >= size)
95+
if (current->allocated_ == false && current->size_ >= size_needed)
9296
{
9397
return current;
9498
}
9599
current = current->next_;
96100
}
101+
97102
return nullptr;
98103
}
99104

@@ -104,12 +109,14 @@ void* splitFreeMemoryBlockIfPossible(MemoryBlock* new_block, size_t size)
104109
return nullptr;
105110
}
106111

107-
size_t remaining_size = new_block->size_ - size;
112+
size_t size_with_canary = size + CANARY_SIZE;
113+
size_t remaining_size = new_block->size_ - size_with_canary;
108114
char one_byte_payload_size_requirement = 1;
109115
if (remaining_size >= BLOCK_METADATA_SIZE + one_byte_payload_size_requirement)
110116
{
111117
void* split_address = getMemoryBlockSplitAddress(new_block, size);
112118
MemoryBlock* new_temp_block = getMemoryBlockFromAddress(split_address);
119+
new_temp_block->magic_ = MAGIC_NUMBER;
113120
new_temp_block->size_ = remaining_size - BLOCK_METADATA_SIZE;
114121
new_temp_block->allocated_ = false;
115122
new_temp_block->next_ = new_block->next_;
@@ -120,17 +127,19 @@ void* splitFreeMemoryBlockIfPossible(MemoryBlock* new_block, size_t size)
120127
}
121128
else
122129
{
123-
new_block->size_ = new_block->size_;
130+
new_block->size_ = new_block->size_ - CANARY_SIZE;
124131
new_block->allocated_ = true;
125132
}
126133

134+
setCanary(new_block);
127135
total_memory_allocated += new_block->size_;
136+
128137
return getPayloadAddress(new_block);
129138
}
130139

131140
void* getMemoryBlockSplitAddress(MemoryBlock* new_block, size_t size)
132141
{
133-
return (reinterpret_cast<char*>(new_block) + BLOCK_METADATA_SIZE + size);
142+
return (reinterpret_cast<char*>(new_block) + BLOCK_METADATA_SIZE + size + CANARY_SIZE);
134143
}
135144

136145
void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_block)
@@ -150,6 +159,18 @@ void insertMemoryBlockAtEnd(MemoryBlock** block_list_head, MemoryBlock* new_bloc
150159
}
151160
}
152161

162+
void setCanary(MemoryBlock* block)
163+
{
164+
if (!block || block->allocated_ == false)
165+
{
166+
return;
167+
}
168+
169+
size_t* canary = reinterpret_cast<size_t*>(reinterpret_cast<char*>(block) +
170+
BLOCK_METADATA_SIZE + block->size_);
171+
*canary = CANARY_VALUE;
172+
}
173+
153174
// helpers
154175
void* getPayloadAddress(MemoryBlock* block)
155176
{
@@ -180,15 +201,28 @@ size_t getSizeOfAllocatedMemoryBlock(MemoryBlock* block)
180201
bool isPointerInHeap(void* ptr)
181202
{
182203
void* current_program_break = sbrk(0);
183-
if (ptr < heap_start || ptr >= current_program_break)
204+
return (ptr >= heap_start && ptr < current_program_break);
205+
}
206+
207+
void* getErrorCodeInVoidPtr(size_t error_code) { return reinterpret_cast<void*>(error_code); }
208+
209+
bool isValidBlock(MemoryBlock* block)
210+
{
211+
return block != nullptr && block->magic_ == MAGIC_NUMBER && block->allocated_ == true;
212+
}
213+
214+
bool checkCanary(MemoryBlock* block)
215+
{
216+
if (!block)
184217
{
185218
return false;
186219
}
187220

188-
return true;
189-
}
221+
size_t* canary = reinterpret_cast<size_t*>(reinterpret_cast<char*>(block) +
222+
BLOCK_METADATA_SIZE + block->size_);
190223

191-
void* getErrorCodeInVoidPtr(size_t error_code) { return reinterpret_cast<void*>(error_code); }
224+
return (*canary == CANARY_VALUE);
225+
}
192226

193227
} // namespace internal
194228
} // namespace mem

0 commit comments

Comments
 (0)