summaryrefslogtreecommitdiffstats
path: root/src/audits
diff options
context:
space:
mode:
Diffstat (limited to 'src/audits')
-rw-r--r--src/audits/Makefile.am9
-rw-r--r--src/audits/memman.cpp238
-rw-r--r--src/audits/memman.h87
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