Compare commits

..

6 commits

Author SHA1 Message Date
3d03ec1e9b Bump version to 2.0, update Changelog.md 2024-06-04 15:43:30 +09:00
4d000a87e0 Use pthreads to mutex-lock malloc/calloc/free 2024-06-04 15:40:57 +09:00
eb716bf65a Impl. checking calloc as well 2024-06-04 15:15:05 +09:00
0e447dc3be Refactorings
Internally use doubly-linked list instead of singly-linked list. Also
minor fixes related to changing use to doubly-linked list.

Removed unnecessary comments.

Move list add/remove code to designated functions.
2024-06-04 15:08:33 +09:00
e33b13a80b Add .gitignore 2024-06-04 14:54:11 +09:00
81ffe0d26d Remove unused type definition
The type definition was a remnant of attempting to use
std::unordered_map, but that used whatever the "malloc" symbol pointed
to.
2024-06-04 14:53:11 +09:00
6 changed files with 134 additions and 36 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build*/

View file

@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
project(AnotherMemCheck) project(AnotherMemCheck)
set(AnotherMemCheck_VERSION 1.0) set(AnotherMemCheck_VERSION 2.0)
set(AnotherMemCheck_SOVERSION 1) set(AnotherMemCheck_SOVERSION 2)
set(AnotherMemCheck_SOURCES set(AnotherMemCheck_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/src/another_memcheck.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/another_memcheck.cc"
@ -28,3 +28,4 @@ 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)

View file

@ -1,5 +1,15 @@
# 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`.

View file

@ -18,56 +18,114 @@ 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) {}
Stats::Stats() : malloced_list(nullptr) { void ListNode::add_to_list(ListNode *tail, Malloced *data) {
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 = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode))); malloced_list_head = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
malloced_list->next = nullptr; malloced_list_tail = reinterpret_cast<ListNode*>(real_malloc(sizeof(ListNode)));
malloced_list->data = nullptr; malloced_list_head->next = malloced_list_tail;
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) {
const Stats *stats = reinterpret_cast<const Stats*>(ptr); Stats *stats = reinterpret_cast<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) {
void *address = real_malloc(size); if(int ret = pthread_mutex_lock(&pthread_mutex); ret == EINVAL) {
if (address != nullptr) { std::clog << "ERROR: pthread mutex not properly initialized!\n";
auto *node = malloced_list; return nullptr;
while (node->next != nullptr) {
node = node->next;
}
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;
} }
void *address = real_malloc(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;
}
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) {
auto *node = malloced_list; if(!ListNode::remove_from_list(malloced_list_head, ptr)) {
decltype(node) parent_node; std::clog << "WARNING: Attempted free of unknown memory location!\n";
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 {
@ -75,11 +133,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; auto *node = malloced_list_head;
while (node->next != nullptr) { while (node->next != nullptr) {
node = node->next; node = node->next;
std::clog << " " << node->data->address << ": size " << node->data->size << '\n'; if (node->data) {
std::clog << " " << node->data->address << ": size " << node->data->size << '\n';
}
} }
} }
} }

View file

@ -1,6 +1,10 @@
#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;
@ -13,6 +17,7 @@ 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 {
@ -24,22 +29,30 @@ namespace SC_AM_Internal {
}; };
struct ListNode { struct ListNode {
ListNode() : next(nullptr), data(nullptr) {} ListNode() : next(nullptr), prev(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; ListNode *malloced_list_head;
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;

View file

@ -1,7 +1,5 @@
// Standard library includes. // Standard library includes.
#include <iostream> #include <iostream>
/*#include <cstdlib>*/
/*#include <cstdio>*/
// Unix includes. // Unix includes.
#include <dlfcn.h> #include <dlfcn.h>
@ -24,6 +22,21 @@ 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";