diff options
Diffstat (limited to 'src/audits')
-rw-r--r-- | src/audits/Makefile.am | 9 | ||||
-rw-r--r-- | src/audits/memman.cpp | 238 | ||||
-rw-r--r-- | src/audits/memman.h | 87 |
3 files changed, 334 insertions, 0 deletions
diff --git a/src/audits/Makefile.am b/src/audits/Makefile.am new file mode 100644 index 0000000..0c72765 --- /dev/null +++ b/src/audits/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = \ + -Wall \ + -I$(top_srcdir)/src + +noinst_LIBRARIES = libaudits.a + +libaudits_a_SOURCES =\ + memman.cpp\ + memman.h diff --git a/src/audits/memman.cpp b/src/audits/memman.cpp new file mode 100644 index 0000000..0c87834 --- /dev/null +++ b/src/audits/memman.cpp @@ -0,0 +1,238 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "memman.h" +#include "log.h" +#include "util.h" + +////////////////////// +// class t_ptr_info +////////////////////// + +t_ptr_info::t_ptr_info(const string &_filename, int _lineno, bool _is_array) : + filename(_filename) +{ + lineno = _lineno; + is_array = _is_array; +} + +////////////////////// +// class t_memman +////////////////////// + +t_memman::t_memman() { + num_new = 0; + num_new_duplicate = 0; + num_delete = 0; + num_delete_mismatch = 0; + num_array_mixing = 0; +} + +void t_memman::trc_new(void *p, const string &filename, int lineno, + bool is_array) +{ + mtx_memman.lock(); + + num_new++; + + // Check if pointer already exists + map<void *, t_ptr_info>::iterator i; + i = pointer_map.find(p); + if (i != pointer_map.end()) { + // Most likely this is an error in the usage of the + // MEMMAN_NEW. A wrong pointer has been passed. + num_new_duplicate++; + + // Unlock now. If memman gets called again via the log, + // there will be no dead lock. + mtx_memman.unlock(); + + log_file->write_header("t_memman::trc_new", + LOG_MEMORY, LOG_WARNING); + log_file->write_raw(filename); + log_file->write_raw(", line "); + log_file->write_raw(lineno); + log_file->write_raw(": pointer to "); + log_file->write_raw(ptr2str(p)); + log_file->write_raw(" has already been allocated.\n"); + log_file->write_raw("It was allocated here: "); + log_file->write_raw(i->second.filename); + log_file->write_raw(", line "); + log_file->write_raw(i->second.lineno); + log_file->write_endl(); + log_file->write_footer(); + return; + } + + t_ptr_info pinfo(filename, lineno, is_array); + pointer_map[p] = pinfo; + + mtx_memman.unlock(); +} + +void t_memman::trc_delete(void *p, const string &filename, int lineno, + bool is_array) +{ + mtx_memman.lock(); + + num_delete++; + + map<void *, t_ptr_info>::iterator i; + i = pointer_map.find(p); + + // Check if the pointer allocation has been reported + if (i == pointer_map.end()) { + num_delete_mismatch++; + mtx_memman.unlock(); + + log_file->write_header("t_memman::trc_delete", + LOG_MEMORY, LOG_WARNING); + log_file->write_raw(filename); + log_file->write_raw(", line "); + log_file->write_raw(lineno); + log_file->write_raw(": pointer to "); + log_file->write_raw(ptr2str(p)); + log_file->write_raw(" is deleted.\n"); + log_file->write_raw("This pointer is not allocated however.\n"); + log_file->write_footer(); + + return; + } + + + bool array_mismatch = (is_array != i->second.is_array); + + // Check mixing of array new/delete + // NOTE: after the pointer has been erased from pointer_map, the + // iterator i is invalid. + // The mutex mtx_memman should be unlocked before logging to + // avoid dead locks. + if (array_mismatch) { + num_array_mixing++; + string allocation_filename = i->second.filename; + int allocation_lineno = i->second.lineno; + bool allocation_is_array = i->second.is_array; + pointer_map.erase(p); + mtx_memman.unlock(); + + log_file->write_header("t_memman::trc_delete", + LOG_MEMORY, LOG_WARNING); + log_file->write_raw(filename); + log_file->write_raw(", line "); + log_file->write_raw(lineno); + log_file->write_raw(": pointer to "); + log_file->write_raw(ptr2str(p)); + log_file->write_raw(" is deleted "); + if (is_array) { + log_file->write_raw("as array (delete []).\n"); + } else { + log_file->write_raw("normally (delete).\n"); + } + log_file->write_raw("But it was allocated "); + if (allocation_is_array) { + log_file->write_raw("as array (new []) \n"); + } else { + log_file->write_raw("normally (new) \n"); + } + log_file->write_raw(allocation_filename); + log_file->write_raw(", line "); + log_file->write_raw(allocation_lineno); + log_file->write_endl(); + log_file->write_footer(); + } else { + pointer_map.erase(p); + mtx_memman.unlock(); + } +} + +void t_memman::report_leaks(void) { + mtx_memman.lock(); + + if (pointer_map.empty()) { + if (num_array_mixing == 0) { + log_file->write_report( + "All pointers have correctly been deallocated.", + "t_memman::report_leaks", + LOG_MEMORY, LOG_INFO); + } else { + log_file->write_header("t_memman::report_leaks", + LOG_MEMORY, LOG_WARNING); + log_file->write_raw("All pointers have been deallocated."), + log_file->write_raw( + "Mixing of array/non-array caused memory loss though."); + log_file->write_footer(); + } + + mtx_memman.unlock(); + return; + } + + log_file->write_header("t_memman::report_leaks", LOG_MEMORY, LOG_WARNING); + log_file->write_raw("The following pointers were never deallocated:\n"); + + for (map<void *, t_ptr_info>::const_iterator i = pointer_map.begin(); + i != pointer_map.end(); i++) + { + log_file->write_raw(ptr2str(i->first)); + log_file->write_raw(" allocated from "); + log_file->write_raw(i->second.filename); + log_file->write_raw(", line "); + log_file->write_raw(i->second.lineno); + log_file->write_endl(); + } + + log_file->write_footer(); + + mtx_memman.unlock(); +} + +void t_memman::report_stats(void) { + mtx_memman.lock(); + + log_file->write_header("t_memman::report_stats", LOG_MEMORY, LOG_INFO); + + log_file->write_raw("Number of allocations: "); + log_file->write_raw(num_new); + log_file->write_endl(); + + log_file->write_raw("Number of duplicate allocations: "); + log_file->write_raw(num_new_duplicate); + log_file->write_endl(); + + log_file->write_raw("Number of de-allocations: "); + log_file->write_raw(num_delete); + log_file->write_endl(); + + log_file->write_raw("Number of mismatched de-allocations: "); + log_file->write_raw(num_delete_mismatch); + log_file->write_endl(); + + log_file->write_raw("Number of array/non-array mixed operations: "); + log_file->write_raw(num_array_mixing); + log_file->write_endl(); + + unsigned long num_unalloc = num_new - num_new_duplicate - + num_delete + num_delete_mismatch; + log_file->write_raw("Number of unallocated pointers: "); + log_file->write_raw(num_unalloc); + log_file->write_endl(); + + log_file->write_footer(); + + mtx_memman.unlock(); +} diff --git a/src/audits/memman.h b/src/audits/memman.h new file mode 100644 index 0000000..e3a25b9 --- /dev/null +++ b/src/audits/memman.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _MEMMAN_H +#define _MEMMAN_H + +#include <string> +#include <map> +#include "threads/mutex.h" + +#define MEMMAN_NEW(ptr) memman->trc_new((ptr), __FILE__, __LINE__) +#define MEMMAN_NEW_ARRAY(ptr) memman->trc_new((ptr), __FILE__, __LINE__, true) +#define MEMMAN_DELETE(ptr) memman->trc_delete((ptr), __FILE__, __LINE__) +#define MEMMAN_DELETE_ARRAY(ptr) memman->trc_delete((ptr), __FILE__, __LINE__, true) +#define MEMMAN_REPORT { memman->report_stats(); memman->report_leaks(); } + +using namespace std; + +// Memory manager +// Trace memory allocations and deallocations + +class t_ptr_info { +public: + // Src file from which pointer has been allocated + string filename; + + // Line number of memman trace command tracing this pointer + int lineno; + + // Indicates if the pointer points to an array + bool is_array; + + t_ptr_info() {}; + t_ptr_info(const string &_filename, int _lineno, bool _is_array); +}; + +class t_memman { +private: + // Map of allocated pointers + map<void *, t_ptr_info> pointer_map; + + // Statistics + unsigned long num_new; // number of new's + unsigned long num_new_duplicate; // number of duplicate new's + unsigned long num_delete; // number of delete's + unsigned long num_delete_mismatch; // number of delete's for without a new + unsigned long num_array_mixing; // number of array/non-array mixes + + // Mutex to protect operations on the memory manager + t_mutex mtx_memman; + +public: + t_memman(); + + // Report pointer allocation + void trc_new(void *p, const string &filename, int lineno, + bool is_array = false); + + // Report pointer deallocation + void trc_delete(void *p, const string &filename, int lineno, + bool is_array = false); + + // Write a memory leak report to log + void report_leaks(void); + + // Write statistics to log + void report_stats(void); +}; + +extern t_memman *memman; + +#endif |