|
leakfinder/allocation_info.hpp 0000664 0001750 0001750 00000001442 11740401715 016674 0 ustar fredrik fredrik #ifndef __allocation_info
#define __allocation_info
#include <vector>
#include <string>
#include <pthread.h>
namespace bornander
{
namespace memory
{
class allocation_info
{
public:
typedef long long address_type;
private:
allocation_info::address_type address;
size_t size;
std::vector<std::string> stacktrace;
pthread_t thread_id;
public:
allocation_info(void* address, size_t size, char** stacktrace, size_t depth, pthread_t thread_id);
allocation_info::address_type get_address() const;
size_t get_size() const;
std::vector<std::string> get_stacktrace() const;
pthread_t get_thread_id() const;
};
}
}
#endif
leakfinder/c_example.c 0000664 0001750 0001750 00000001064 11740035522 015123 0 ustar fredrik fredrik #include <stdlib.h>
#include <stdio.h>
void foo(int size)
{
int* data = malloc(sizeof(int) * size);
// Uncomment this to stop leak
//free(data);
}
void bar(int size)
{
char *data = malloc(sizeof(char) * size);
foo(size);
// Uncomment this to stop leak
//free(data);
}
void foobar(int size)
{
bar(size);
}
int main(void)
{
printf("leakfinder C example app\n");
printf("This application is expected to leak\n");
foobar(8);
foobar(16);
printf("leakfinder C example app all done\n");
return 0;
}
leakfinder/cpp_example.cpp 0000664 0001750 0001750 00000001535 11753520221 016025 0 ustar fredrik fredrik #include<iostream>
class my_class_a
{
private:
int* leak;
int* no_leak;
public:
my_class_a()
{
leak = new int;
no_leak = new int;
}
~my_class_a()
{
delete no_leak;
}
};
class my_class_b
{
private:
my_class_a a_instance;
public:
void foo()
{
int* leak = new int;
}
void bar()
{
foo();
}
void foobar()
{
bar();
}
};
void cpp_function()
{
char* leak = new char;
}
extern "C" void c_function()
{
cpp_function();
}
int main(void)
{
std::cout << "leakfinder C++ thread example app" << std::endl;
std::cout << "This application is expected to leak" << std::endl;
my_class_b b;
b.foobar();
b.foo();
c_function();
std::cout << "leakfinder C++ thread example app all done" << std::endl;
return 0;
}
leakfinder/c_thread_example.c 0000664 0001750 0001750 00000002022 11753517742 016462 0 ustar fredrik fredrik #include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
void foo(int size)
{
int* data = malloc(sizeof(int) * size);
// Uncomment this to stop leak
//free(data);
}
void bar(int size)
{
char *data = malloc(sizeof(char) * size);
foo(size);
// Uncomment this to stop leak
//free(data);
}
void foobar(int size)
{
bar(size);
}
void* thread_run(void* ptr)
{
char* message = (char*)ptr;
printf("Caller %s with id %ld\n", message, pthread_self());
foobar(32);
}
int main(void)
{
printf("leakfinder C thread example app\n");
printf("This application is expected to leak on multiple threads\n");
pthread_t thread1, thread2;
char *message1 = "Thread 1";
char *message2 = "Thread 2";
pthread_create(&thread1, NULL, thread_run, (void*)message1);
pthread_create(&thread2, NULL, thread_run, (void*)message2);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("leakfinder C thread example app all done\n");
return 0;
}
leakfinder/leakfinder.c 0000664 0001750 0001750 00000002335 11737567756 015325 0 ustar fredrik fredrik #include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#define __USE_GNU
#include <dlfcn.h>
class allocation_info
{
private:
public:
};
static bool isExternalSource=true;
static void* (*real_malloc)(size_t)=0;
static void (*real_free)(void*)=0;
static void __mtrace_init(void)
{
real_malloc = (void*(*)(size_t))dlsym(RTLD_NEXT, "malloc");
if (real_malloc == 0) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
real_free = (void(*)(void*))dlsym(RTLD_NEXT, "free");
if (real_free == 0) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
extern "C" void *malloc(size_t size)
{
if(real_malloc==0)
__mtrace_init();
void *p = real_malloc(size);
if (isExternalSource)
{
isExternalSource = false;
printf("Allocating %d bytes\n", size);
isExternalSource = true;
}
return p;
}
extern "C" void free(void* ptr)
{
if(real_free==0)
__mtrace_init();
int address = (int)ptr;
real_free(ptr);
if (isExternalSource)
{
isExternalSource = false;
printf("Freed memory at %d \n", address);
isExternalSource = true;
}
}
leakfinder/leakfinder.cpp 0000664 0001750 0001750 00000006730 11753521446 015650 0 ustar fredrik fredrik #include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <execinfo.h>
#include <pthread.h>
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <dlfcn.h>
#include "allocation_info.hpp"
using namespace bornander::memory;
using namespace std;
static void compile_allocation() __attribute__((destructor));
static pthread_mutex_t cs_mutex = PTHREAD_MUTEX_INITIALIZER;
static size_t allocation_count = 0;
static vector<allocation_info> allocations;
static const size_t max_frame_depth = 128;
static bool isExternalSource = true;
static void* (*sys_malloc)(size_t) = 0;
static void (*sys_free)(void*) = 0;
static void initialize_functions(void)
{
sys_malloc = reinterpret_cast<void*(*)(size_t)>(dlsym(RTLD_NEXT, "malloc"));
if (sys_malloc == 0)
cerr << "leakfinder failed to read malloc function; " << dlerror() << endl;
sys_free = reinterpret_cast<void(*)(void*)>(dlsym(RTLD_NEXT, "free"));
if (sys_free == 0)
cerr << "leakfinder failed to read free function; " << dlerror() << endl;
}
extern "C" void* malloc(size_t size)
{
if (sys_malloc == 0)
initialize_functions();
void* ptr = sys_malloc(size);
if (isExternalSource)
{
pthread_t thread_id = pthread_self();
pthread_mutex_lock(&cs_mutex);
isExternalSource = false;
++allocation_count;
void* frames[max_frame_depth];
size_t stack_size = backtrace(frames, max_frame_depth);
char** stacktrace = backtrace_symbols(frames, stack_size);
allocation_info allocation(ptr, size, stacktrace, stack_size, thread_id);
allocations.push_back(allocation);
sys_free(stacktrace);
isExternalSource = true;
pthread_mutex_unlock(&cs_mutex);
}
return ptr;
}
extern "C" void free(void* ptr)
{
if (sys_free == 0)
initialize_functions();
allocation_info::address_type address = reinterpret_cast<allocation_info::address_type>(ptr);
sys_free(ptr);
if (isExternalSource)
{
pthread_mutex_lock(&cs_mutex);
isExternalSource = false;
for (int i = 0; i < allocations.size(); ++i)
{
allocation_info allocation = allocations[i];
if (allocation.get_address() == address)
{
allocations.erase(allocations.begin() + i);
break;
}
}
isExternalSource = true;
pthread_mutex_unlock(&cs_mutex);
}
}
void compile_allocation()
{
isExternalSource = false;
if (allocations.empty())
{
cout << "leakfinder found no leaks, not one of the " << allocation_count;
cout << " allocations was not released." << endl;
}
else
{
cout << "leakfinder detected that " << allocations.size();
cout << " out of " << allocation_count << " allocations was not released." << endl;
for (int i = 0; i < allocations.size(); ++i)
{
allocation_info allocation = allocations[i];
cout << "Leak " << (i+1) << "@0x" << hex << allocation.get_thread_id() << dec;
cout << "; leaked " << allocation.get_size() << " bytes at position 0x";
cout << hex << allocation.get_address() << dec << endl;
vector<string> stacktrace = allocation.get_stacktrace();
for (int j = 0; j < stacktrace.size(); ++j)
{
cout << "\t" << stacktrace[j] << endl;
}
}
}
}
leakfinder/makefile 0000664 0001750 0001750 00000001020 11760654461 014525 0 ustar fredrik fredrik all: leakfinder.so c_example c_thread_example cpp_example
leakfinder.so: allocation_info.hpp allocation_info.cpp leakfinder.cpp
g++ -shared -fPIC allocation_info.cpp leakfinder.cpp -o leakfinder.so -lpthread -ldl
c_example: c_example.c
cc -rdynamic c_example.c -o c_example
c_thread_example: c_thread_example.c
cc -rdynamic c_thread_example.c -lpthread -o c_thread_example
cpp_example: cpp_example.cpp
g++ -rdynamic cpp_example.cpp -o cpp_example
clean:
rm -rf leakfinder.so c_example c_thread_example cpp_example
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Article videos
Oakmead Apps Android Games
21 Feb 2014: Best VB.NET Article of January 2014 - Second Prize
18 Oct 2013: Best VB.NET article of September 2013
23 Jun 2012: Best C++ article of May 2012
20 Apr 2012: Best VB.NET article of March 2012
22 Feb 2010: Best overall article of January 2010
22 Feb 2010: Best C# article of January 2010