Compare commits
No commits in common. "3d03ec1e9b5c178112f436b9c49e7083058a60a8" and "fd0da26f83b51ea098c643a0cf6d5ef26f269f6b" have entirely different histories.
3d03ec1e9b
...
fd0da26f83
6 changed files with 34 additions and 132 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
/build*/
|
|
|
@ -1,8 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
project(AnotherMemCheck)
|
project(AnotherMemCheck)
|
||||||
|
|
||||||
set(AnotherMemCheck_VERSION 2.0)
|
set(AnotherMemCheck_VERSION 1.0)
|
||||||
set(AnotherMemCheck_SOVERSION 2)
|
set(AnotherMemCheck_SOVERSION 1)
|
||||||
|
|
||||||
set(AnotherMemCheck_SOURCES
|
set(AnotherMemCheck_SOURCES
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/another_memcheck.cc"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/another_memcheck.cc"
|
||||||
|
@ -28,4 +28,3 @@ set_target_properties(AnotherMemCheck PROPERTIES VERSION ${AnotherMemCheck_VERSI
|
||||||
SOVERSION ${AnotherMemCheck_SOVERSION})
|
SOVERSION ${AnotherMemCheck_SOVERSION})
|
||||||
|
|
||||||
target_compile_features(AnotherMemCheck PUBLIC cxx_std_20)
|
target_compile_features(AnotherMemCheck PUBLIC cxx_std_20)
|
||||||
target_link_libraries(AnotherMemCheck PUBLIC pthread)
|
|
||||||
|
|
10
Changelog.md
10
Changelog.md
|
@ -1,15 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Version 2.0
|
|
||||||
|
|
||||||
Minor refactorings.
|
|
||||||
|
|
||||||
Change internal implementation of linked list to be doubly-linked.
|
|
||||||
|
|
||||||
Add support for calloc.
|
|
||||||
|
|
||||||
Add pthreads to mutex-lock malloc/calloc/free.
|
|
||||||
|
|
||||||
## Version 1.0
|
## Version 1.0
|
||||||
|
|
||||||
Initial version with working `AnotherMemCheck`.
|
Initial version with working `AnotherMemCheck`.
|
||||||
|
|
|
@ -18,114 +18,56 @@ namespace SC_AM_Internal {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *(*real_malloc)(std::size_t) = nullptr;
|
void *(*real_malloc)(std::size_t) = nullptr;
|
||||||
void *(*real_calloc)(std::size_t, std::size_t) = nullptr;
|
|
||||||
void (*real_free)(void*) = nullptr;
|
void (*real_free)(void*) = nullptr;
|
||||||
|
|
||||||
Malloced::Malloced() : address(nullptr), size(0) {}
|
Malloced::Malloced() : address(nullptr), size(0) {}
|
||||||
Malloced::Malloced(void *address, std::size_t size) : address(address), size(size) {}
|
Malloced::Malloced(void *address, std::size_t size) : address(address), size(size) {}
|
||||||
|
|
||||||
void ListNode::add_to_list(ListNode *tail, Malloced *data) {
|
Stats::Stats() : malloced_list(nullptr) {
|
||||||
ListNode *new_node = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
|
|
||||||
new_node->next = tail;
|
|
||||||
new_node->prev = tail->prev;
|
|
||||||
tail->prev->next = new_node;
|
|
||||||
tail->prev = new_node;
|
|
||||||
|
|
||||||
new_node->data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ListNode::remove_from_list(ListNode *head, void *ptr) {
|
|
||||||
ListNode *node = head;
|
|
||||||
while (node != nullptr) {
|
|
||||||
node = node->next;
|
|
||||||
if (node->data && node->data->address == ptr) {
|
|
||||||
node->prev->next = node->next;
|
|
||||||
node->next->prev = node->prev;
|
|
||||||
real_free(node->data);
|
|
||||||
real_free(node);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Stats::Stats() : malloced_list_head(nullptr), malloced_list_tail(nullptr), pthread_mutex{.__align=0} {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stats::initialize() {
|
void Stats::initialize() {
|
||||||
malloced_list_head = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
|
malloced_list = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
|
||||||
malloced_list_tail = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
|
malloced_list->next = nullptr;
|
||||||
malloced_list_head->next = malloced_list_tail;
|
malloced_list->data = nullptr;
|
||||||
malloced_list_head->prev = nullptr;
|
|
||||||
malloced_list_tail->next = nullptr;
|
|
||||||
malloced_list_tail->prev = malloced_list_head;
|
|
||||||
malloced_list_head->data = nullptr;
|
|
||||||
malloced_list_tail->data = nullptr;
|
|
||||||
|
|
||||||
pthread_mutex_init(&pthread_mutex, nullptr);
|
|
||||||
|
|
||||||
on_exit([] ([[maybe_unused]] int status, void *ptr) {
|
on_exit([] ([[maybe_unused]] int status, void *ptr) {
|
||||||
Stats *stats = reinterpret_cast<Stats*>(ptr);
|
const Stats *stats = reinterpret_cast<const Stats*>(ptr);
|
||||||
stats->print_status();
|
stats->print_status();
|
||||||
stats->cleanup();
|
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stats::cleanup() {
|
|
||||||
pthread_mutex_destroy(&pthread_mutex);
|
|
||||||
// TODO maybe cleanup list, but it is the end of the program.
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Stats::do_malloc(std::size_t size) {
|
void *Stats::do_malloc(std::size_t size) {
|
||||||
if(int ret = pthread_mutex_lock(&pthread_mutex); ret == EINVAL) {
|
|
||||||
std::clog << "ERROR: pthread mutex not properly initialized!\n";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *address = real_malloc(size);
|
void *address = real_malloc(size);
|
||||||
if (address != nullptr) {
|
if (address != nullptr) {
|
||||||
Malloced *data = reinterpret_cast<Malloced*>(real_malloc(sizeof(Malloced)));
|
auto *node = malloced_list;
|
||||||
data->address = address;
|
while (node->next != nullptr) {
|
||||||
data->size = size;
|
node = node->next;
|
||||||
ListNode::add_to_list(malloced_list_tail, data);
|
}
|
||||||
|
node->next = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
|
||||||
|
node->next->next = nullptr;
|
||||||
|
node->next->data = reinterpret_cast<Malloced*>(real_malloc(sizeof(Malloced)));
|
||||||
|
node->next->data->address = address;
|
||||||
|
node->next->data->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&pthread_mutex);
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *Stats::do_calloc(std::size_t n, std::size_t size) {
|
|
||||||
if(int ret = pthread_mutex_lock(&pthread_mutex); ret == EINVAL) {
|
|
||||||
std::clog << "ERROR: pthread mutex not properly initialized!\n";
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *address = real_calloc(n, size);
|
|
||||||
if (address != nullptr) {
|
|
||||||
Malloced *data = reinterpret_cast<Malloced*>(real_malloc(sizeof(Malloced)));
|
|
||||||
data->address = address;
|
|
||||||
data->size = size;
|
|
||||||
ListNode::add_to_list(malloced_list_tail, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&pthread_mutex);
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stats::do_free(void *ptr) {
|
void Stats::do_free(void *ptr) {
|
||||||
if(int ret = pthread_mutex_lock(&pthread_mutex); ret == EINVAL) {
|
|
||||||
std::clog << "ERROR: pthread mutex not properly initialized!\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
if(!ListNode::remove_from_list(malloced_list_head, ptr)) {
|
auto *node = malloced_list;
|
||||||
std::clog << "WARNING: Attempted free of unknown memory location!\n";
|
decltype(node) parent_node;
|
||||||
|
while (node->next != nullptr) {
|
||||||
|
parent_node = node;
|
||||||
|
node = node->next;
|
||||||
|
if (node->data && node->data->address == ptr) {
|
||||||
|
real_free(node->data);
|
||||||
|
parent_node->next = node->next;
|
||||||
|
real_free(node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&pthread_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stats::print_status() const {
|
void Stats::print_status() const {
|
||||||
|
@ -133,15 +75,13 @@ namespace SC_AM_Internal {
|
||||||
// it is expected for the OS to reclaim memory from stopped processes and
|
// it is expected for the OS to reclaim memory from stopped processes and
|
||||||
// this function only runs at the end of program execution.
|
// this function only runs at the end of program execution.
|
||||||
std::clog << "List of unfreed memory:\n";
|
std::clog << "List of unfreed memory:\n";
|
||||||
auto *node = malloced_list_head;
|
auto *node = malloced_list;
|
||||||
while (node->next != nullptr) {
|
while (node->next != nullptr) {
|
||||||
node = node->next;
|
node = node->next;
|
||||||
|
|
||||||
if (node->data) {
|
|
||||||
std::clog << " " << node->data->address << ": size " << node->data->size << '\n';
|
std::clog << " " << node->data->address << ": size " << node->data->size << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// vim: et sw=2 ts=2 sts=2
|
// vim: et sw=2 ts=2 sts=2
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#ifndef SEODISPARATE_COM_ANOTHER_MEMCHECK_H
|
#ifndef SEODISPARATE_COM_ANOTHER_MEMCHECK_H
|
||||||
#define SEODISPARATE_COM_ANOTHER_MEMCHECK_H
|
#define SEODISPARATE_COM_ANOTHER_MEMCHECK_H
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <pthread.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SC_AM_Internal {
|
namespace SC_AM_Internal {
|
||||||
// Forward declaration.
|
// Forward declaration.
|
||||||
struct Stats;
|
struct Stats;
|
||||||
|
@ -17,7 +13,6 @@ namespace SC_AM_Internal {
|
||||||
constexpr unsigned int DATA_ITEMS_SIZE = 500;
|
constexpr unsigned int DATA_ITEMS_SIZE = 500;
|
||||||
|
|
||||||
extern void *(*real_malloc)(std::size_t size);
|
extern void *(*real_malloc)(std::size_t size);
|
||||||
extern void *(*real_calloc)(std::size_t n, std::size_t size);
|
|
||||||
extern void (*real_free)(void *ptr);
|
extern void (*real_free)(void *ptr);
|
||||||
|
|
||||||
struct Malloced {
|
struct Malloced {
|
||||||
|
@ -29,30 +24,22 @@ namespace SC_AM_Internal {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListNode {
|
struct ListNode {
|
||||||
ListNode() : next(nullptr), prev(nullptr), data(nullptr) {}
|
ListNode() : next(nullptr), data(nullptr) {}
|
||||||
|
|
||||||
static void add_to_list(ListNode *tail, Malloced *data);
|
|
||||||
/// Returns true if removed.
|
|
||||||
static bool remove_from_list(ListNode *head, void *ptr);
|
|
||||||
|
|
||||||
ListNode *next;
|
ListNode *next;
|
||||||
ListNode *prev;
|
|
||||||
Malloced *data;
|
Malloced *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using MapDataType = std::pair<const void*, Malloced>;
|
||||||
|
|
||||||
struct Stats {
|
struct Stats {
|
||||||
Stats();
|
Stats();
|
||||||
|
|
||||||
ListNode *malloced_list_head;
|
ListNode *malloced_list;
|
||||||
ListNode *malloced_list_tail;
|
|
||||||
pthread_mutex_t pthread_mutex;
|
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void cleanup();
|
|
||||||
|
|
||||||
void *do_malloc(std::size_t size);
|
void *do_malloc(std::size_t size);
|
||||||
void *do_calloc(std::size_t n, std::size_t size);
|
|
||||||
void do_free(void *ptr);
|
void do_free(void *ptr);
|
||||||
|
|
||||||
void print_status() const;
|
void print_status() const;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Standard library includes.
|
// Standard library includes.
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
/*#include <cstdlib>*/
|
||||||
|
/*#include <cstdio>*/
|
||||||
|
|
||||||
// Unix includes.
|
// Unix includes.
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
@ -22,21 +24,6 @@ extern "C" {
|
||||||
return SC_AM_Internal::stats->do_malloc(size);
|
return SC_AM_Internal::stats->do_malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *calloc(std::size_t n, std::size_t size) {
|
|
||||||
std::clog << "attempting to calloc size: " << size << "...\n";
|
|
||||||
|
|
||||||
if (SC_AM_Internal::real_calloc == nullptr) {
|
|
||||||
SC_AM_Internal::real_calloc = reinterpret_cast<void*(*)(std::size_t, std::size_t)>(
|
|
||||||
dlsym(RTLD_NEXT, "calloc"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SC_AM_Internal::stats == nullptr) {
|
|
||||||
SC_AM_Internal::stats = SC_AM_Internal::get_init_stats();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SC_AM_Internal::stats->do_calloc(n, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(void *ptr) {
|
void free(void *ptr) {
|
||||||
std::clog << "attempting to free...\n";
|
std::clog << "attempting to free...\n";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue