1 /*
2  *  memstats.cpp
3  *  OpenLieroX
4  *
5  *  memstats implementation for memstats.h
6  *
7  *  Created by Albert Zeyer on 03.09.09.
8  *  code under LGPL
9  *
10  */
11 
12 #ifdef MEMSTATS
13 
14 #include <new>
15 #include <iostream>
16 #include <map>
17 #include <string>
18 #include "Debug.h"
19 #include "Mutex.h"
20 
21 #undef new
22 #undef delete
23 
24 #define SAFEALLOC_MAXALLOCS (1024 * 1024)
25 #define SAFEALLOC_POOLSIZE (50 * 1024 * 1024)
26 
27 struct SafeAlloc {
28 	char* p;
29 	size_t s;
30 	SafeAlloc *left, *right;
31 
SafeAllocSafeAlloc32 	SafeAlloc() : p(NULL), s(0), left(NULL), right(NULL) {}
isUsedSafeAlloc33 	bool isUsed() const { return p != NULL; }
resetSafeAlloc34 	void reset() { p = NULL; s = 0; left = NULL; right = NULL; }
initPoolMemSafeAlloc35 	void initPoolMem() { *(SafeAlloc**)p = this; }
userPtSafeAlloc36 	void* userPt() const { return p + extraSpacePerAlloc; }
userSizeSafeAlloc37 	size_t userSize() const { return s - SafeAlloc::extraSpacePerAlloc; }
38 
39 	static const size_t extraSpacePerAlloc = sizeof(SafeAlloc*);
40 };
41 
42 static SafeAlloc* safeAllocs = NULL; // sorted list
43 static char safeAllocs_Mem[SAFEALLOC_MAXALLOCS * sizeof(SafeAlloc)];
44 static SafeAlloc *safeAlloc_first = NULL;
45 static SafeAlloc *safeAlloc_lastAlloc = NULL;
46 static char safeAllocPool[SAFEALLOC_POOLSIZE];
47 static Mutex* safeAlloc_mutex = NULL;
48 static char safeAlloc_mutex_Mem[sizeof(Mutex)];
49 
safeAlloc_init()50 void safeAlloc_init() {
51 	safeAlloc_mutex = (Mutex*) &safeAlloc_mutex_Mem[0];
52 	new (safeAlloc_mutex) Mutex;
53 
54 	safeAllocs = (SafeAlloc*) &safeAllocs_Mem[0];
55 	for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i)
56 		new (&safeAllocs[i]) SafeAlloc;
57 }
58 
safeAlloc_uninit()59 void safeAlloc_uninit() {
60 	for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i)
61 		safeAllocs[i] . ~SafeAlloc();
62 	safeAllocs = NULL;
63 	safeAlloc_mutex -> ~Mutex();
64 	safeAlloc_mutex = NULL;
65 }
66 
safeAlloc_listEmpty()67 bool safeAlloc_listEmpty() { return safeAlloc_first == NULL; }
68 
safeAlloc_allocNum(SafeAlloc * a)69 int safeAlloc_allocNum(SafeAlloc* a) { return int(a - &safeAllocs[0]); }
70 
safeAlloc_dbg(const char * txt,SafeAlloc * a)71 void safeAlloc_dbg(const char* txt, SafeAlloc* a) {
72 	printf("%s alloc %i @%i (#%i) for %i bytes\n",
73 		   txt,
74 		   safeAlloc_allocNum(a),
75 		   int(a->userPt()),
76 		   int(a->p - &safeAllocPool[0]),
77 		   int(a->userSize()));
78 }
79 
safeAlloc_sanityCheck(SafeAlloc * a)80 size_t safeAlloc_sanityCheck(SafeAlloc* a) {
81 	if(a < &safeAllocs[0]) {
82 		printf("wrong: alloc @%i is left outside array\n", int(a));
83 		return 0;
84 	}
85 
86 	if(a >= &safeAllocs[SAFEALLOC_MAXALLOCS]) {
87 		printf("wrong: alloc @%i is right outside array\n", int(a));
88 		return 0;
89 	}
90 
91 	if(a->isUsed()) {
92 		if(a->s <= SafeAlloc::extraSpacePerAlloc) printf("wrong: alloc %i has invalid size %i\n", safeAlloc_allocNum(a), a->s);
93 		if(a->left >= a) printf("wrong: alloc %i has invalid left link\n", safeAlloc_allocNum(a));
94 		if(a->left == NULL && safeAlloc_first != a) printf("wrong: alloc %i has no left link\n", safeAlloc_allocNum(a));
95 		if(a->right != NULL && a->right <= a) printf("wrong: alloc %i has invalid right link\n", safeAlloc_allocNum(a));
96 
97 		// all right followers MUST be used
98 		size_t allocNum = 1;
99 		for(SafeAlloc* b = a; ; ) {
100 			if(!b->isUsed()) {
101 				printf("wrong: alloc %i has unused right follower %i\n", safeAlloc_allocNum(a), safeAlloc_allocNum(b));
102 				break;
103 			}
104 			if(b->right == NULL) {
105 				// all next items in array must be unused
106 				for(SafeAlloc* c = b + 1; c < &safeAllocs[SAFEALLOC_MAXALLOCS]; ++c) {
107 					if(c->isUsed()) {
108 						printf("wrong: alloc %i has used past-end %i right follower %i\n", safeAlloc_allocNum(a), safeAlloc_allocNum(b), safeAlloc_allocNum(c));
109 						break;
110 					}
111 				}
112 				break;
113 			}
114 			b = b->right;
115 			allocNum++;
116 		}
117 		return allocNum;
118 	}
119 	else {
120 		if(a->s != 0) printf("wrong: unused alloc %i has size = %i\n", safeAlloc_allocNum(a), a->s);
121 		if(a->left != NULL) {
122 			printf("wrong: unused alloc %i has left link\n", safeAlloc_allocNum(a));
123 			if(a->left >= a) printf("wrong: unused alloc %i has invalid left link\n", safeAlloc_allocNum(a));
124 		}
125 		if(a->right != NULL) {
126 			printf("wrong: unused alloc %i has right link\n", safeAlloc_allocNum(a));
127 			if(a->right <= a) printf("wrong: unused alloc %i has invalid right link\n", safeAlloc_allocNum(a));
128 		}
129 	}
130 
131 	return 0;
132 }
133 
safeAlloc_sanityCheckAll()134 void safeAlloc_sanityCheckAll() {
135 	size_t allocNum = 0;
136 	for(size_t i = 0; i < SAFEALLOC_MAXALLOCS; ++i) {
137 		safeAlloc_sanityCheck(&safeAllocs[i]);
138 		if(safeAllocs[i].isUsed()) allocNum++;
139 	}
140 
141 	if(!safeAlloc_listEmpty()) {
142 		if(!safeAlloc_first->isUsed()) printf("wrong: first alloc %i is unused\n", safeAlloc_allocNum(safeAlloc_first));
143 
144 		size_t allocNum2 = safeAlloc_sanityCheck(safeAlloc_first);
145 		if(allocNum != allocNum2) printf("wrong: absolute allocs (%i) is different than linked list allocs (%i)\n", allocNum, allocNum2);
146 	}
147 }
148 
149 typedef std::pair<SafeAlloc*,SafeAlloc*> LRpair;
150 
safeAlloc_findFreeAt(SafeAlloc * start,size_t n)151 LRpair safeAlloc_findFreeAt(SafeAlloc* start, size_t n) {
152 	for(SafeAlloc* a = start; a; a = a->right) {
153 		SafeAlloc* b = a->right;
154 
155 		// Note: obsolete security check
156 		if(!a->isUsed()) {
157 			printf("SafeAlloc: something is REALLY messed up!\n");
158 			printf("sanity check of %i:\n", safeAlloc_allocNum(a));
159 			safeAlloc_sanityCheck(a);
160 			printf("sanity check everything:\n");
161 			safeAlloc_sanityCheckAll();
162 			printf("sanity check first (%i):\n", safeAlloc_allocNum(safeAlloc_first));
163 			safeAlloc_sanityCheck(safeAlloc_first);
164 			safeAlloc_dbg("mess a", a);
165 			return LRpair(a, b); // cannot really recover, so who cares...
166 		}
167 
168 		// Note: obsolete security check
169 		if(b && !b->isUsed()) {
170 			printf("SafeAlloc: something is rightly messed up!\n");
171 			safeAlloc_sanityCheck(b);
172 			safeAlloc_dbg("mess b", b);
173 			return LRpair(a, b); // cannot really recover, so who cares...
174 		}
175 
176 		if(a + 1 == b || a + 1 == &safeAllocs[SAFEALLOC_MAXALLOCS])
177 			// we cannot make a list entry here, so continue searching
178 			continue;
179 
180 		const char* rightEnd = b ? b->p : &safeAllocPool[SAFEALLOC_POOLSIZE];
181 		char* leftStart = a->p + a->s;
182 
183 		// Note: obsolete security check
184 		if(rightEnd < leftStart) {
185 			printf("SafeAlloc: something is messed up!\n");
186 			continue; // doesn't really make sense, but we cannot do anything else
187 		}
188 
189 		// Note: obsolete security check
190 		if(b && b->left != a) {
191 			printf("SafeAlloc: linked list is messed up!\n");
192 		}
193 
194 		const size_t neededSize = n + SafeAlloc::extraSpacePerAlloc;
195 		if(size_t(rightEnd - leftStart) >= neededSize)
196 			// we have enough place here, return
197 			return LRpair(a, b);
198 	}
199 
200 	// nothing free, return invalid pair
201 	return LRpair(&safeAllocs[SAFEALLOC_MAXALLOCS], NULL);
202 }
203 
safeAlloc_findFree(size_t n)204 LRpair safeAlloc_findFree(size_t n) {
205 	if(safeAlloc_listEmpty())
206 		return LRpair(NULL, NULL);
207 
208 	LRpair ret = LRpair(&safeAllocs[SAFEALLOC_MAXALLOCS], NULL);
209 	if(safeAlloc_lastAlloc) {
210 		ret = safeAlloc_findFreeAt(safeAlloc_lastAlloc, n);
211 		if(ret.first < &safeAllocs[SAFEALLOC_MAXALLOCS]) return ret;
212 	}
213 
214 	if(safeAlloc_first > &safeAllocs[0]) {
215 		const char* rightEnd = safeAlloc_first->p;
216 		char* leftStart = &safeAllocPool[0];
217 
218 		const size_t neededSize = n + SafeAlloc::extraSpacePerAlloc;
219 		if(size_t(rightEnd - leftStart) >= neededSize)
220 			// we have enough place here, return
221 			return LRpair(NULL, safeAlloc_first);
222 	}
223 
224 	return safeAlloc_findFreeAt(safeAlloc_first, n);
225 }
226 
safeAlloc_alloc(size_t n)227 void* safeAlloc_alloc(size_t n) {
228 	Mutex::ScopedLock lock(*safeAlloc_mutex);
229 	LRpair pair = safeAlloc_findFree(n);
230 
231 	if(pair.first == NULL) {
232 		// everything free or before first entry
233 
234 		if(n + SafeAlloc::extraSpacePerAlloc > SAFEALLOC_POOLSIZE) {
235 			// no chance
236 			printf("SafeAlloc alloc: cannot allocate %i bytes, it's more than our whole pool supports\n", n);
237 			return NULL;
238 		}
239 
240 		// init list
241 		safeAllocs[0].reset();
242 		safeAllocs[0].right = safeAlloc_first; if(safeAlloc_first) safeAlloc_first->left = &safeAllocs[0];
243 		safeAllocs[0].p = &safeAllocPool[0];
244 		safeAllocs[0].s = n + SafeAlloc::extraSpacePerAlloc;
245 		safeAllocs[0].initPoolMem();
246 		safeAlloc_first = &safeAllocs[0];
247 		safeAlloc_lastAlloc = safeAlloc_first;
248 		//safeAlloc_dbg("init first", &safeAllocs[0]);
249 		return safeAllocs[0].userPt();
250 	}
251 
252 	SafeAlloc* a = pair.first + 1;
253 	if(a < &safeAllocs[SAFEALLOC_MAXALLOCS]) {
254 		// we fit after pair.first
255 
256 		a->reset();
257 		a->left = pair.first; pair.first->right = a;
258 		a->right = pair.second; if(pair.second) pair.second->left = a;
259 		a->p = a->left->p + a->left->s; // directly next to the left alloc
260 		a->s = n + SafeAlloc::extraSpacePerAlloc;
261 		a->initPoolMem();
262 		safeAlloc_lastAlloc = a;
263 		//safeAlloc_dbg("init", a);
264 		return a->userPt();
265 	}
266 
267 	// nothing free
268 	printf("SafeAlloc alloc: cannot allocate %i bytes, nothing free anymore\n", n);
269 	return NULL;
270 }
271 
safeAlloc_free(void * p)272 void safeAlloc_free(void* p) {
273 	Mutex::ScopedLock lock(*safeAlloc_mutex);
274 
275 	if((size_t)p < SafeAlloc::extraSpacePerAlloc) {
276 		printf("SafeAlloc free: pointer %i is invalid!\n", int(p));
277 		return;
278 	}
279 
280 	SafeAlloc** const a = (SafeAlloc**)p - 1;
281 	if((char*)a < &safeAllocPool[0] || (char*)a + sizeof(SafeAlloc*) - 1 >= &safeAllocPool[SAFEALLOC_POOLSIZE]) {
282 		printf("SafeAlloc free: pointer %i is not inside pool and thus invalid!\n", int(p));
283 		return;
284 	}
285 
286 	SafeAlloc* const al = *a;
287 
288 	if(al < &safeAllocs[0] || al >= &safeAllocs[SAFEALLOC_MAXALLOCS]) {
289 		printf("SafeAlloc free: pointer %i is messed up!\n", int(p));
290 		return;
291 	}
292 
293 	if(((size_t)al - (size_t)&safeAllocs[0]) % sizeof(SafeAlloc) != 0) {
294 		printf("SafeAlloc free: pointer %i is fucked up!\n", int(p));
295 		return;
296 	}
297 
298 	if(!al->isUsed()) {
299 		printf("SafeAlloc free: pointer %i is strange, perhaps already freed?!\n", int(p));
300 		return;
301 	}
302 
303 	if(safeAlloc_listEmpty()) {
304 		printf("SafeAlloc free: pointer %i must be wrong, there aren't any allocations!\n", int(p));
305 		return;
306 	}
307 
308 	if(al->userPt() != p) {
309 		printf("SafeAlloc free: pointer %i doesn't behave well!\n", int(p));
310 		return;
311 	}
312 
313 	if(al->left == NULL && safeAlloc_first != al) {
314 		printf("SafeAlloc free: pointer %i is old!\n", int(p));
315 		return;
316 	}
317 
318 	if(al < safeAlloc_first) {
319 		printf("SafeAlloc free: pointer %i is wrong, it must point to an old alloc!\n", int(p));
320 		return;
321 	}
322 
323 	if(al == safeAlloc_first && al->left != NULL) {
324 		printf("SafeAlloc free: pointer %i has wrong linked list info!\n", int(p));
325 		return;
326 	}
327 
328 	// everything seems sane
329 	// clean up now
330 	//safeAlloc_dbg("free", al);
331 	if(safeAlloc_lastAlloc == al)
332 		safeAlloc_lastAlloc = al->left;
333 	if(al->left == NULL) {
334 		safeAlloc_first = al->right;
335 		if(al->right) al->right->left = NULL;
336 	} else {
337 		al->left->right = al->right;
338 		if(al->right) al->right->left = al->left;
339 	}
340 	al->reset();
341 }
342 
343 
344   template<typename _Tp>
345     class safe_allocator
346     {
347     public:
348       typedef size_t     size_type;
349       typedef ptrdiff_t  difference_type;
350       typedef _Tp*       pointer;
351       typedef const _Tp* const_pointer;
352       typedef _Tp&       reference;
353       typedef const _Tp& const_reference;
354       typedef _Tp        value_type;
355 
356       template<typename _Tp1>
357         struct rebind
358 	  { typedef safe_allocator<_Tp1> other; };
359 
safe_allocator()360 	  safe_allocator() throw() { }
361 
safe_allocator(const safe_allocator &)362 	  safe_allocator(const safe_allocator&) throw() { }
363 
364       template<typename _Tp1>
safe_allocator(const safe_allocator<_Tp1> &)365         safe_allocator(const safe_allocator<_Tp1>&) throw() { }
366 
~safe_allocator()367       ~safe_allocator() throw() { }
368 
369       pointer
address(reference __x) const370       address(reference __x) const { return &__x; }
371 
372       const_pointer
address(const_reference __x) const373       address(const_reference __x) const { return &__x; }
374 
375       // NB: __n is permitted to be 0.  The C++ standard says nothing
376       // about what the return value is when __n == 0.
377       pointer
allocate(size_type __n,const void * =0)378       allocate(size_type __n, const void* = 0)
379       {
380         pointer __ret = static_cast<_Tp*>(safeAlloc_alloc(__n * sizeof(_Tp)));
381         if (!__ret)
382           throw std::bad_alloc();
383         return __ret;
384       }
385 
386       // __p is not permitted to be a null pointer.
387       void
deallocate(pointer __p,size_type)388       deallocate(pointer __p, size_type)
389       { safeAlloc_free(static_cast<void*>(__p)); }
390 
391       size_type
max_size() const392       max_size() const throw()
393 	  { return SAFEALLOC_POOLSIZE - SafeAlloc::extraSpacePerAlloc; }
394 
395       // _GLIBCXX_RESOLVE_LIB_DEFECTS
396       // 402. wrong new expression in [some_] allocator::construct
397       void
construct(pointer __p,const _Tp & __val)398       construct(pointer __p, const _Tp& __val)
399       { ::new(__p) value_type(__val); }
400 
401       void
destroy(pointer __p)402       destroy(pointer __p) { __p->~_Tp(); }
403     };
404 
405   template<typename _Tp>
406     inline bool
operator ==(const safe_allocator<_Tp> &,const safe_allocator<_Tp> &)407     operator==(const safe_allocator<_Tp>&, const safe_allocator<_Tp>&)
408     { return true; }
409 
410   template<typename _Tp>
411     inline bool
operator !=(const safe_allocator<_Tp> &,const safe_allocator<_Tp> &)412     operator!=(const safe_allocator<_Tp>&, const safe_allocator<_Tp>&)
413     { return false; }
414 
415 
416 typedef std::basic_string<char, std::char_traits<char>, safe_allocator<char> > String;
417 
dbgError(const String & err)418 static void dbgError(const String& err) {
419 	printf("memstats error: %s\n", err.c_str());
420 	RaiseDebugger();
421 	DumpCallstackPrintf();
422 	fflush(0);
423 }
424 
dbgMsg(const String & msg)425 static void dbgMsg(const String& msg) {
426 	printf("memstats: %s\n", msg.c_str());
427 	fflush(0);
428 }
429 
430 template<typename T>
IntToStr(T num,int base=10)431 String IntToStr(T num, int base = 10) {
432 	String buf;
433 	if(num < 0) { buf = "-"; num = -num; }
434 
435 	do {
436 		buf = "0123456789abcdefghijklmnopqrstuvwxyz"[num % base] + buf;
437 		num /= base;
438 	} while(num);
439 
440 	return buf;
441 }
442 
SizeAsStr(size_t sum)443 String SizeAsStr(size_t sum) {
444 	if(sum < 2*1024)
445 		return IntToStr(sum) + " B";
446 	else if(sum < 2*1024*1024)
447 		return IntToStr(sum / 1024) + " KB";
448 	else
449 		return IntToStr(sum / (1024*1024)) + " MB";
450 }
451 
findLastPathSep(const String & path)452 size_t findLastPathSep(const String& path) {
453 	size_t slash = path.rfind('\\');
454 	size_t slash2 = path.rfind('/');
455 	if(slash == String::npos)
456 		slash = slash2;
457 	else if(slash2 != String::npos)
458 		slash = std::max(slash, slash2);
459 	return slash;
460 }
461 
GetBaseFilename(const String & filename)462 String GetBaseFilename(const String& filename) {
463 	size_t p = findLastPathSep(filename);
464 	if(p == String::npos) return filename;
465 	return filename.substr(p+1);
466 }
467 
468 
469 typedef String FileName;
470 typedef int Line;
471 typedef std::pair<FileName,Line> ObjType;
472 typedef std::pair<ObjType,size_t> AllocInfo;
473 
ObjTypeAsStr(const ObjType & obj)474 String ObjTypeAsStr(const ObjType& obj) {
475 	return obj.first + ":" + IntToStr(obj.second);
476 }
477 
AllocInfoAsStr(const AllocInfo & al)478 String AllocInfoAsStr(const AllocInfo& al) {
479 	return ObjTypeAsStr(al.first) + "#" + IntToStr(al.second);
480 }
481 
482 typedef std::map<ObjType, size_t, std::less<ObjType>, safe_allocator< std::pair<const ObjType, size_t> > > Allocations;
483 typedef std::map<void*, AllocInfo, std::less<void*>, safe_allocator< std::pair<void* const, AllocInfo> > > AllocInfoMap;
484 
485 struct MemStats {
486 	Mutex mutex;
487 	Allocations allocSums;
488 	AllocInfoMap allocInfos;
489 };
490 static MemStats* stats = NULL;
491 static bool finalCleanup = false;
492 
initMemStats()493 static bool initMemStats() {
494 	if(finalCleanup) return false;
495 	if(stats == NULL) {
496 		printf("--- MemStats initialisation ---\n");
497 		safeAlloc_init();
498 		stats = (MemStats*) malloc(sizeof(MemStats));
499 		new(stats) MemStats;
500 	}
501 	return true;
502 }
503 
504 struct MemStats_FinalCleanup {
~MemStats_FinalCleanupMemStats_FinalCleanup505 	~MemStats_FinalCleanup() {
506 		if(stats != NULL) {
507 			stats -> ~MemStats();
508 			free(stats);
509 			stats = NULL;
510 			safeAlloc_uninit();
511 			finalCleanup = true;
512 		}
513 	}
514 } memStats_finalCleanup;
515 
516 
operator new(size_t size,dmalloc_t,const char * file,int line)517 void * operator new (size_t size, dmalloc_t, const char* file, int line) {
518 	void* p = malloc(size);
519 
520 	if(initMemStats()) {
521 		ObjType obj( GetBaseFilename(String(file)), line );
522 
523 		if(p == NULL) {
524 			dbgError("out-of-memory @" + ObjTypeAsStr(obj));
525 			printMemStats();
526 			throw std::bad_alloc();
527 		}
528 
529 		Mutex::ScopedLock lock(stats->mutex);
530 		stats->allocSums[obj] += size;
531 		stats->allocInfos[p] = AllocInfo(obj, size);
532 	}
533 
534 	return p;
535 }
536 
operator new[](size_t size,dmalloc_t,const char * file,int line)537 void * operator new [] (size_t size, dmalloc_t, const char* file, int line) {
538 	return :: operator new (size, dmalloc_t(), file, line);
539 }
540 
operator new(size_t size)541 void * operator new (size_t size) throw (std::bad_alloc) {
542 	return :: operator new (size, dmalloc_t(), "??", 0);
543 }
544 
operator new[](size_t size)545 void * operator new [] (size_t size) throw (std::bad_alloc) {
546 	return :: operator new (size, dmalloc_t(), "??", 0);
547 }
548 
operator new(std::size_t size,const std::nothrow_t &)549 void* operator new(std::size_t size, const std::nothrow_t&) throw() {
550 	try {
551 		return :: operator new (size, dmalloc_t(), "??", 0);
552 	}
553 	catch(std::bad_alloc) {
554 		return NULL;
555 	}
556 }
557 
operator new[](std::size_t size,const std::nothrow_t &)558 void* operator new[](std::size_t size, const std::nothrow_t&) throw() {
559 	try {
560 		return :: operator new (size, dmalloc_t(), "??", 0);
561 	}
562 	catch(std::bad_alloc) {
563 		return NULL;
564 	}
565 }
566 
operator delete(void * p)567 void operator delete (void * p) throw() {
568 	if(!initMemStats()) {
569 		free(p);
570 		return;
571 	}
572 
573 	Mutex::ScopedLock lock(stats->mutex);
574 
575 	AllocInfoMap::iterator i = stats->allocInfos.find(p);
576 	if(i == stats->allocInfos.end()) {
577 		dbgError("deleting invalid pointer");
578 		dbgMsg("* pointer: " + IntToStr((int)p));
579 		if(stats->allocInfos.size() == 0) {
580 			dbgMsg("* none allocations are made right now");
581 			return;
582 		}
583 		i = stats->allocInfos.lower_bound(p);
584 		if(i == stats->allocInfos.begin()) {
585 			dbgMsg("* pointer is before first allocation");
586 			dbgMsg("* first allocation @" + IntToStr((int)i->first));
587 			return;
588 		}
589 		--i; // go before pointer
590 		dbgMsg("* below alloc is " + AllocInfoAsStr(i->second) + " @" + IntToStr((int)i->first));
591 		if((size_t)i->first + i->second.second > (size_t)p)
592 			dbgMsg("* pointer IS inside that range");
593 		else
594 			dbgMsg("* pointer is NOT inside that range");
595 		return;
596 	}
597 
598 	const AllocInfo allocInfo = i->second;
599 	stats->allocInfos.erase(i);
600 	size_t& allocSum = stats->allocSums[allocInfo.first];
601 	if(allocSum >= allocInfo.second)
602 		allocSum -= allocInfo.second;
603 	else {
604 		dbgError("delete: allocation info messed up, allocSum too small");
605 		dbgMsg("* pointer: " + IntToStr((int)p));
606 		dbgMsg("* allocSum: " + IntToStr(allocSum));
607 		dbgMsg("* alloc size: " + IntToStr(allocInfo.second));
608 		allocSum = 0;
609 	}
610 
611 	free(p);
612 }
613 
operator delete[](void * p)614 void operator delete [] (void * p) throw() {
615 	:: operator delete (p);
616 }
617 
operator delete(void * p,const std::nothrow_t &)618 void operator delete(void* p, const std::nothrow_t&) throw() {
619 	:: operator delete (p);
620 }
621 
operator delete[](void * p,const std::nothrow_t &)622 void operator delete[](void* p , const std::nothrow_t&) throw() {
623 	:: operator delete (p);
624 }
625 
printMemStats()626 void printMemStats() {
627 	if(stats) {
628 		dbgMsg("-- MemStats --");
629 
630 		typedef std::multimap<size_t, ObjType, std::less<size_t>, safe_allocator< std::pair<const size_t,ObjType> > > Allocs;
631 		Allocs allocs;
632 		size_t sum = 0;
633 		{
634 			Mutex::ScopedLock lock(stats->mutex);
635 			dbgMsg("allocs: " + IntToStr(stats->allocInfos.size()));
636 			dbgMsg("num of different alloc types: " + IntToStr(stats->allocSums.size()));
637 
638 			// sort all alloc types by alloc sum
639 			for(Allocations::iterator i = stats->allocSums.begin(); i != stats->allocSums.end(); ++i) {
640 				allocs.insert( Allocs::value_type(i->second, i->first) );
641 				sum += i->second;
642 			}
643 		}
644 
645 		dbgMsg("allocated mem: " + SizeAsStr(sum));
646 		int count = 30;
647 		for(Allocs::reverse_iterator i = allocs.rbegin(); i != allocs.rend(); ++i) {
648 			dbgMsg(". " + ObjTypeAsStr(i->second) + " - " + SizeAsStr(i->first));
649 			count--;
650 			if(count <= 0) break;
651 		}
652 		dbgMsg(".");
653 	}
654 	else
655 		// NOTE: we cannot use dbgMsg because this needs the safeAlloc system which is init together with memstats
656 		printf("* MemStats not initialised *\n");
657 }
658 
659 
660 #endif
661 
662