Debugging another memory bug.

This commit is contained in:
Kyle Isom 2023-10-09 19:59:21 -07:00
parent 85ff28360b
commit 8122ca265d
11 changed files with 253 additions and 43 deletions

View File

@ -13,6 +13,7 @@
#define PROT_RW (PROT_WRITE|PROT_READ)
#elif defined(__WIN64__) || defined(__WIN32__)
#include <Windows.h>
#include <fileapi.h>
#endif
@ -144,7 +145,47 @@ Arena::Create(const char *path, size_t fileSize, mode_t mode)
int
Arena::Open(const char *path)
{
HANDLE fHandle;
size_t fSize;
size_t fRead = 0;
size_t fRemaining;
auto cursor = this->store;
OVERLAPPED overlap;
fHandle = CreateFileA(
(LPSTR)path,
GENERIC_READ,
(FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE),
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (fHandle == INVALID_HANDLE_VALUE) {
return -1;
}
if (!GetFileSizeEx(fHandle, reinterpret_cast<PLARGE_INTEGER>(&fSize))) {
CloseHandle(fHandle);
return -1;
}
this->SetAlloc(fSize);
fRemaining = fSize;
while (fRemaining != 0) {
overlap.Offset = (fSize - fRemaining);
if (!ReadFile(fHandle, cursor, fSize, reinterpret_cast<LPDWORD>(&fRead), &overlap)) {
CloseHandle(fHandle);
this->Destroy();
return -1;
}
cursor += fRead;
fRemaining -= fRead;
}
CloseHandle(fHandle);
return 0;
}
#endif
@ -227,7 +268,7 @@ operator<<(std::ostream &os, Arena &arena)
{
auto cursor = arena.Store();
char cursorString[33] = {0};
snprintf(cursorString, 32, "%#016lx", cursor);
snprintf(cursorString, 32, "%#016llx", cursor);
os << "Arena<";
switch (arena.Type()) {

View File

@ -1,3 +1,9 @@
/// @file Arena.h
/// @author K. Isom
/// @brief Memory management using an arena.
/// @section DESCRIPTION
/// Arena defines a memory management backend for pre-allocating memory.
#ifndef KIMODEM_ARENA_H
#define KIMODEM_ARENA_H
@ -41,6 +47,8 @@ public:
int MemoryMap(int memFileDes, size_t memSize); // Arena will own fd.
int Create(const char *path, size_t fileSize, mode_t mode);
int Open(const char *path);
#elif defined(__WIN64__) || defined(__WIN32__)
int Open(const char *path);
#endif
uint8_t *NewCursor() const { return this->store; }

116
Buffer.cc
View File

@ -4,14 +4,17 @@
#include <cassert>
#include <cstring>
#include "Buffer.h"
#include <ios>
#include <iostream>
#include <iomanip>
#include "Buffer.h"
namespace klib {
constexpr size_t defaultCapacity = 32;
constexpr size_t maxReasonableLine = 8192;
constexpr size_t defaultCapacity = 32;
constexpr size_t maxReasonableLine = 8192;
static size_t
@ -21,7 +24,7 @@ nearestPower(size_t x)
return 0;
}
std::cout << "x -> ";
std::cout << "x -> ";
x--;
@ -32,48 +35,48 @@ nearestPower(size_t x)
x |= x >> 16;
x |= x >> 32;
std::cout << x + 1 << std::endl;
std::cout << x + 1 << std::endl;
return x+1;
return x + 1;
}
Buffer::Buffer()
: contents(nullptr), length(0), capacity(0)
{
this->Resize(defaultCapacity);
this->Resize(defaultCapacity);
}
Buffer::Buffer(size_t initialCapacity)
: contents(nullptr), length(0), capacity(0)
{
this->Resize(initialCapacity);
this->Resize(initialCapacity);
}
Buffer::Buffer(const char *data)
: contents(nullptr), length(0), capacity(0)
{
size_t datalen = strnlen(data, maxReasonableLine);
size_t datalen = strnlen(data, maxReasonableLine);
this->Append((uint8_t *)data, datalen);
this->Append((uint8_t *) data, datalen);
}
bool
Buffer::Append(const char *s)
{
size_t slen = strnlen(s, maxReasonableLine);
size_t slen = strnlen(s, maxReasonableLine);
return this->Append((uint8_t *)s, slen);
return this->Append((uint8_t *) s, slen);
}
bool
Buffer::Append(uint8_t *data, size_t datalen)
{
auto resized = false;
auto newCap = this->mustGrow(datalen);
auto resized = false;
auto newCap = this->mustGrow(datalen);
if (newCap > 0) {
this->Resize(newCap);
@ -96,16 +99,16 @@ Buffer::Append(uint8_t c)
bool
Buffer::Insert(size_t index, const char *s)
{
size_t slen = strnlen(s, maxReasonableLine);
size_t slen = strnlen(s, maxReasonableLine);
return this->Insert(index, (uint8_t *)(s), slen);
return this->Insert(index, (uint8_t *) (s), slen);
}
bool
Buffer::Insert(size_t index, uint8_t *data, size_t datalen)
{
auto resized = this->shiftRight(index, datalen);
auto resized = this->shiftRight(index, datalen);
memcpy(this->contents + index, data, datalen);
this->length += datalen;
@ -140,7 +143,7 @@ void
Buffer::Resize(size_t newCapacity)
{
if (newCapacity < this->length) {
return;
newCapacity = nearestPower(this->length + newCapacity);
}
auto newContents = new uint8_t[newCapacity];
@ -151,6 +154,7 @@ Buffer::Resize(size_t newCapacity)
}
delete this->contents;
this->contents = nullptr;
this->contents = newContents;
this->capacity = newCapacity;
}
@ -158,7 +162,7 @@ Buffer::Resize(size_t newCapacity)
size_t
Buffer::Trim()
{
size_t projectedCapacity = nearestPower(this->length);
size_t projectedCapacity = nearestPower(this->length);
assert(projectedCapacity >= length);
@ -173,9 +177,9 @@ Buffer::Trim()
void
Buffer::Clear()
{
if (this->length == 0) {
return;
}
if (this->length == 0) {
return;
}
memset(this->contents, 0, this->length);
this->length = 0;
}
@ -183,15 +187,23 @@ Buffer::Clear()
void
Buffer::Reclaim()
{
std::cout << "clear" << std::endl;
this->Clear();
if (this->contents == nullptr) {
assert(this->length == 0);
assert(this->capacity == 0);
return;
}
std::cout << "nullptr check" << std::endl;
if (this->contents == nullptr) {
std::cout << "assert checks" << std::endl;
assert(this->length == 0);
assert(this->capacity == 0);
return;
}
std::cout << "delete " << this->Capacity() << "B" << std::endl;
this->HexDump(std::cout);
delete this->contents;
this->contents = nullptr;
std::cout << "reset contents" << std::endl;
this->contents = nullptr;
std::cout << "reset capacity" << std::endl;
this->capacity = 0;
}
@ -207,20 +219,56 @@ Buffer::mustGrow(size_t delta) const
}
void
Buffer::HexDump(std::ostream &os)
{
#ifndef NDEBUG
size_t index = 0;
os << std::hex;
os << std::setfill('0');
for (index = 0; index < this->length; index++) {
bool eol = (index % 16) == 0;
if (eol && (index > 0)) {
os << std::endl;
}
if (eol) {
os << std::setw(8);
os << index << " ";
os << std::setw(2);
}
os << (unsigned short)this->contents[index];
if ((index % 15) != 0 || (index == 0)) {
os << " ";
}
}
if ((index % 16) != 0) {
os << std::endl;
}
os << std::setw(0) << std::dec;
#endif
}
bool
Buffer::shiftRight(size_t offset, size_t delta)
{
auto resized = false;
auto newCap = this->mustGrow(delta);
auto resized = false;
auto newCap = this->mustGrow(delta);
if (newCap > 0) {
this->Resize(newCap);
resized = true;
}
if (this->length == 0) return 0;
if (this->length == 0) return 0;
memmove(this->contents+(offset+delta), this->contents+offset, this->length);
memmove(this->contents + (offset + delta), this->contents + offset, this->length);
return resized;
}
@ -232,13 +280,13 @@ Buffer::shiftLeft(size_t offset, size_t delta)
// this->contents[i] = this->contents[i+delta];
// }
memmove(this->contents+offset, this->contents+(offset+delta), this->length);
memmove(this->contents + offset, this->contents + (offset + delta), this->length);
return this->Trim() != 0;
}
uint8_t&
uint8_t &
Buffer::operator[](size_t index)
{
return this->contents[index];

View File

@ -5,6 +5,7 @@
#ifndef KGE_BUFFER_H
#define KGE_BUFFER_H
#include <iostream>
#include <cstdint>
@ -39,6 +40,8 @@ public:
void Clear();
void Reclaim();
void HexDump(std::ostream &os);
uint8_t &operator[](size_t index);
private:
size_t mustGrow(size_t delta) const;

10
CMakeDocs.txt Normal file
View File

@ -0,0 +1,10 @@
# Doxygen support for klib.
find_package(Doxygen)
if (${DOXYGEN_FOUND})
doxygen_add_docs(klib_docs
${HEADER_FILES} ${SOURCE_FILES}
USE_STAMP_FILE)
endif ()

View File

@ -19,13 +19,22 @@ set(HEADER_FILES
Arena.h
Buffer.h
Dictionary.h
Test.h
TLV.h)
set(SOURCE_FILES
Arena.cc
Buffer.cc
Dictionary.cc
Test.cc
TLV.cc)
add_library(klib STATIC
Arena.cc
Buffer.cc
Dictionary.cc
TLV.cc)
TLV.cc
)
install(TARGETS klib LIBRARY DESTINATION ${PREFIX}/lib)
install(FILES ${HEADER_FILES} DESTINATION include/klib)
install(FILES klibConfig.cmake DESTINATION share/klib/cmake)
@ -45,11 +54,12 @@ add_executable(buffer_test bufferTest.cc)
target_link_libraries(buffer_test klib)
add_test(bufferTest buffer_test)
include(CMakePack.txt)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
klibConfig.cmake
VERSION ${PACKAGE_VERSION}
COMPATIBILITY AnyNewerVersion
)
)
include(CMakePack.txt)
include(CMakeDocs.txt)

42
Test.cc Normal file
View File

@ -0,0 +1,42 @@
//
// Created by kyle on 2023-10-09.
//
#include "Test.h"
#include <iostream>
#include <cassert>
namespace klib {
void
TestAssert(bool condition, std::string message = "Assertion failed.")
{
#if defined(NDEBUG)
if (!condition) {
throw AssertionFailed(message);
}
#else
if (!condition) {
std::cerr << message << std::endl;
}
assert(condition);
#endif
}
AssertionFailed::AssertionFailed(std::string message) : msg(message)
{
}
char *
AssertionFailed::what() const noexcept
{
return const_cast<char *>(this->msg.c_str());
}
} // namespace klib

31
Test.h Normal file
View File

@ -0,0 +1,31 @@
//
// Created by kyle on 2023-10-09.
//
#include <string>
#ifndef KLIB_TEST_H
#define KLIB_TEST_H
namespace klib {
void
TestAssert(bool condition, std::string message);
class AssertionFailed : public std::exception {
public:
explicit AssertionFailed(std::string message);
char *what() const noexcept override;
public:
std::string msg;
};
} // namespace klib
#endif //KLIB_TEST_H

View File

@ -18,12 +18,26 @@ main(int argc, char *argv[])
std::cout << buffer.Contents() << std::endl;
std::cout << "remove end" << std::endl;
buffer.Remove(buffer.Length() - 1);
buffer.Remove(0, 5);
buffer.Insert(0, 'g');
buffer.Insert(1, (uint8_t *) "oodbye", 6);
std::cout << "remove start" << std::endl;
buffer.Remove(0, 5);
std::cout << "insert char" << std::endl;
buffer.Insert(0, 'g');
std::cout << "insert chunk" << std::endl;
buffer.Insert(1, (uint8_t *) "oodbye", 6);
std::cout << "cruel" << std::endl;
buffer.Insert(9, (uint8_t *)"cruel ", 6);
std::cout << buffer.Contents() << std::endl;
buffer.HexDump(std::cout);
std::cout << "reclaim" << std::endl;
buffer.Reclaim();
std::cout << "append" << std::endl;
buffer.Append("and now for something completely different...");
std::cout << buffer.Contents() << std::endl;

View File

@ -48,7 +48,7 @@ main(int argc, const char *argv[])
abort();
}
#else
if (AllocNewArena(arena, ARENA_SIZE) == -1) {
if (arena.SetAlloc(ARENA_SIZE) == -1) {
abort();
}
#endif

View File

@ -4,10 +4,13 @@
#include <iostream>
#include "Arena.h"
#include "Test.h"
#include "TLV.h"
#include "testFixtures.h"
using namespace klib;
static uint8_t arenaBuffer[ARENA_SIZE];