aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/kernel/memleaks.cpp
blob: 151eb1d703390698bdf6ca6e431d0829a47161b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// -----------------------------------------------------------------------------
// This file is part of Broken Sword 2.5
// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsd�rfer
//
// Broken Sword 2.5 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.
//
// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// -----------------------------------------------------------------------------

#ifdef BS_MEMLOG

// Die folgende Zeile stellt sicher, dass alle Objekte in dieser Datei vor allen anderen erstellt und nach allen anderen
// zerst�rt werden.
// Damit wird sichergestellt, dass z.B. Singletons nicht f�lschlicherweise als Memory-Leaks erkannt werden.
// TODO Visual C++ 8 kommt mit der aktuellen Implementation nicht klar und st�rzt sowohl beim Start aus auch beim
// Beenden ab. Es muss eine Alternativimplementation her. An sichersten ist es wohl, wenn gar keine STL-Objekte benutzt
// werden.
// #pragma warning (disable : 4074)
// #pragma init_seg(compiler)

#include "sword25/kernel/filesystemutil.h"

#include "sword25/kernel/memlog_off.h"
#include <vector>
#include <algorithm>
#include <string>

#include <stdio.h>
#include <string.h>

typedef struct
{
	unsigned int		address;
	unsigned int		size;
	std::string			file;
	unsigned int		line;
} ALLOC_INFO;

static const char * MEMLEAK_LOG_FILE = "memory_leaks.txt";
static const unsigned int BUCKET_COUNT = 1021;
std::vector< std::vector<ALLOC_INFO> > TrackData(BUCKET_COUNT);

static unsigned int TotalSize = 0;

// Diese Klasse stellt sicher, dass beim Programmende, das Memory-Leak Log geschrieben wird.
static class LeakDumper
{
public:
	LeakDumper() : OutputFilename(BS_FileSystemUtil::GetInstance().GetUserdataDirectory() + "\\" + MEMLEAK_LOG_FILE)
	{
		// Sicherstellen, dass das Ausgabeverzeichnis f�r die Datei existiert.
		BS_FileSystemUtil::GetInstance().CreateDirectory(BS_FileSystemUtil::GetInstance().GetUserdataDirectory());
	}

	~LeakDumper()
	{
		DumpUnfreed(OutputFilename.c_str());
	}

	std::string OutputFilename;
} LeakDumperInstance;

void DumpUnfreed(const char * OutputFilename)
{
	FILE * Log = fopen(OutputFilename, "w");
	fputs("MEMORY LEAK REPORT:\n----------------------\n", Log);
	std::vector< std::vector<ALLOC_INFO> >::iterator BucketIter = TrackData.begin();
	for (; BucketIter != TrackData.end(); ++BucketIter)
	{
		std::vector<ALLOC_INFO>::iterator Iter = (*BucketIter).begin();
		for (; Iter != (*BucketIter).end(); ++Iter)
		{
			ALLOC_INFO & CurItem = (*Iter);
			fprintf(Log, "%-50s LINE:%d ADDRESS:0x%x SIZE:%d\n",
					CurItem.file.c_str(),
					CurItem.line,
					CurItem.address,
					CurItem.size);
		}
	}

	fprintf(Log, "----------------------\nTotal unfreed bytes: %d\n", TotalSize);

	fclose(Log);
}

void AddTrack(unsigned int addr,  unsigned int asize,  const char *fname, unsigned int lnum)
{
	std::vector<ALLOC_INFO> & CurBucket = TrackData[(addr >> 3) % BUCKET_COUNT];
	ALLOC_INFO Info;
	Info.address = addr;
	Info.size = asize;
	Info.file = fname;
	Info.line = lnum;
	CurBucket.push_back(Info);

	TotalSize += asize;
}

void RemoveTrack(unsigned int addr)
{
	if (addr != 0 && TrackData.size() == BUCKET_COUNT)
	{
		std::vector<ALLOC_INFO> & CurBucket = TrackData[(addr >> 3) % BUCKET_COUNT];
		std::vector<ALLOC_INFO>::iterator Iter = CurBucket.begin();
		for (; Iter != CurBucket.end(); ++Iter)
		{
			if ((*Iter).address == addr)
			{
				TotalSize -= (*Iter).size;
				
				std::swap(*Iter, CurBucket.back());
				CurBucket.pop_back();
				return;
			}
		}
	}
}

#endif