1
/*------------------------------------------------------------------------------
2
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
4
* Distributable under the terms of either the Apache License (Version 2.0) or
5
* the GNU Lesser General Public License, as specified in the COPYING file.
6
------------------------------------------------------------------------------*/
7
#include "CLucene/StdHeader.h"
8
#include "CLucene/util/Misc.h"
10
bool _lucene_disable_debuglogging = true; //if LUCENE_ENABLE_CONSTRUCTOR_LOG is on, dont do log if this is true
11
bool _lucene_run_objectcheck = false; //run a memory check before deleting objects
12
int _lucene_counter_break = -1; //to break at this item, change this
13
//and put break points at points below
18
#ifdef LUCENE_ENABLE_MEMLEAKTRACKING
19
int32_t _instance_counter = 0; //counter for initnumber
22
int32_t refcount; ///times this has been used
23
char* value; ///reference to the the basefile
24
}; //structure for name counting
29
};//structure for pointer-filename references
31
typedef CL_NS(util)::CLSet<const char*,_file*,Compare::Char,Deletor::Dummy,Deletor::Void<_file> > defFile;
32
typedef CL_NS(util)::CLSet<LuceneBase*,_pointers*,Compare::Void<LuceneBase>,Deletor::Dummy,Deletor::Void<_pointers> > defPointer;
33
typedef CL_NS(util)::CLSet<const void*,_pointers*,Compare::Void<const void>,Deletor::Dummy,Deletor::Void<_pointers> > defVoid;
35
DEFINE_MUTEX(memleak_lock)
36
defFile LuceneBase_Files(false,true); //list of filenames used
37
defPointer LuceneBase_Pointers(false,true); //list of pointers counted
38
defVoid LuceneBase_Voids(false,true); //list of arbitary data added
40
//variables to trim filenames to just the base names
41
char _files_trim_string[CL_MAX_DIR];
42
int32_t _files_trim_start=-1;
44
//trim the filename and return the refcounted _file* structure
45
_file* get_file(const char* file){
46
if ( _files_trim_start == -1 ){
47
//this trims the start of the name file name so
48
//that the whole of the filename is not stored - more asthetic :)
49
//need to find the base
50
_files_trim_start = strlen(__FILE__) - 21; //(length of debug/memtracking.cpp)
51
strcpy(_files_trim_string,__FILE__);
52
_files_trim_string[_files_trim_start] = 0;
54
if ( strncmp(file,_files_trim_string,_files_trim_start) == 0 ){
55
//this file should be within the same directory area as we found lucenebase.cpp
56
//to be, lets trim the start
57
file+=_files_trim_start;
60
//now return an existing files structure (with refcount++) or create a new one
61
defFile::iterator itr = LuceneBase_Files.find((const char*)file);
62
if ( itr != LuceneBase_Files.end() ){
63
_file* bf = itr->second;
67
_file* ref = new _file;
68
ref->value = new char[strlen(file)+1]; //cannot use _CL_NEWARRAY otherwise recursion
69
strcpy(ref->value,file);
72
LuceneBase_Files.insert(pair<const char*,_file*>(ref->value,ref));
77
void remove_file(_file* bf){
79
if ( bf->refcount <= 0 ){
80
defFile::iterator fi = LuceneBase_Files.find(bf->value);
81
CND_PRECONDITION(fi!=LuceneBase_Files.end(),"fi==NULL");
83
LuceneBase_Files.removeitr(fi);
87
#ifdef LUCENE_ENABLE_CONSTRUCTOR_LOG
88
void constructor_log(const char* type,const char* file,const int line, const int size){
89
if ( _lucene_disable_debuglogging ){
90
FILE* f = fopen("clucene.log","a");
91
char buf[CL_MAX_DIR+5];
92
sprintf(buf,"%s,%s,%d,%d\n",type,file,line,size);
93
fwrite(buf,sizeof(char),strlen(buf),f);
97
#define CONSTRUCTOR_LOG(type,file,line,size) constructor_log(type,file,line,size)
99
#define CONSTRUCTOR_LOG(type,file,line,size)
102
////////////////////////////////////////////////////////////////////////////////
103
// the _CLNEW&_CLDELETE new/delete operators
104
////////////////////////////////////////////////////////////////////////////////
105
void* LuceneBase::operator new (size_t size, const char * file, int32_t line)
107
SCOPED_LOCK_MUTEX(memleak_lock)
109
void* p = malloc (size);
110
LuceneBase* lb = (LuceneBase*)p;
112
//create the pointer struct
113
_file* br = get_file(file);
114
_pointers* bp = new _pointers;
116
bp->initnumber = _instance_counter++;
119
//associate this object with the pointer
120
lb->__cl_initnum = bp->initnumber;
123
if ( _lucene_counter_break == lb->__cl_initnum )
124
CLDebugBreak(); //put break point here
126
//add the pointer object
127
LuceneBase_Pointers.insert(pair<LuceneBase*,_pointers*>(lb, bp));
129
CONSTRUCTOR_LOG("newobj",file,line,size);
132
void LuceneBase::operator delete (void *p, char const * file, int32_t line)
134
SCOPED_LOCK_MUTEX(memleak_lock)
136
LuceneBase* lb=(LuceneBase*)p;
138
defPointer::iterator itr = LuceneBase_Pointers.find(lb);
139
if ( itr != LuceneBase_Pointers.end() ){
140
_pointers* bp = itr->second;
141
remove_file(bp->file);
143
LuceneBase_Pointers.removeitr(itr);
150
///////////////////////////////////////////////////////////////////////////
151
// the generic new/delete operators
152
///////////////////////////////////////////////////////////////////////////
153
void* LuceneBase::operator new (size_t size)
155
SCOPED_LOCK_MUTEX(memleak_lock)
157
void* p = malloc (size);
158
LuceneBase* lb = (LuceneBase*)p;
160
//create the pointer struct
161
_file* br = get_file("undefined");
162
_pointers* bp = new _pointers;
164
bp->initnumber = _instance_counter++;
167
//associate this object with the pointer
168
lb->__cl_initnum = bp->initnumber;
171
if ( _lucene_counter_break == lb->__cl_initnum )
174
//add the pointer object
175
LuceneBase_Pointers.insert(pair<LuceneBase*,_pointers*>(lb,bp));
177
CONSTRUCTOR_LOG("newobj","unknown",-1,size);
180
void LuceneBase::operator delete (void *p)
182
SCOPED_LOCK_MUTEX(memleak_lock)
184
LuceneBase* lb=(LuceneBase*)p;
186
defPointer::iterator itr = LuceneBase_Pointers.find(lb);
187
if ( itr != LuceneBase_Pointers.end() ){
188
_pointers* bp = itr->second;
189
remove_file(bp->file);
190
LuceneBase_Pointers.removeitr(itr);
197
///////////////////////////////////////////////////////////////////////////
198
// other memtracking functions
199
///////////////////////////////////////////////////////////////////////////
200
void LuceneBase::__cl_unregister(const void* obj){
201
SCOPED_LOCK_MUTEX(memleak_lock)
203
LuceneBase* lb=(LuceneBase*)obj;
204
defPointer::iterator itr = LuceneBase_Pointers.find(lb);
205
CND_PRECONDITION(itr != LuceneBase_Pointers.end(),"__cl_unregister object not found");
206
_pointers* bp = itr->second;
207
LuceneBase_Pointers.removeitr(itr);
210
void* LuceneBase::__cl_voidpadd(void* data, const char* file, int line,size_t size){
211
SCOPED_LOCK_MUTEX(memleak_lock)
213
_file* br = get_file(file);
214
_pointers* bp = new _pointers;
216
bp->initnumber = _instance_counter++;
219
LuceneBase_Voids.insert(pair<void*,_pointers*>(data,bp));
220
CONSTRUCTOR_LOG("newarr",file,line,size);
223
void LuceneBase::__cl_voidpremove(const void* data, const char* file, int line){
224
SCOPED_LOCK_MUTEX(memleak_lock)
225
defVoid::iterator itr = LuceneBase_Voids.find(data);
226
if ( itr != LuceneBase_Voids.end() ){
227
_pointers* bp = itr->second;
228
remove_file(bp->file);
229
LuceneBase_Voids.removeitr(itr);
231
printf("Data deleted when not added with _CL_NEWARRAY in %s at %d\n",file,line);
236
////////////////////////////////////////////////////////////
239
////////////////////////////////////////////////////////////
240
//The lucene base memory leak printout functions
241
////////////////////////////////////////////////////////////
243
void __internalcl_PrintUnclosedObject(bool isObject, string& sb,_pointers* bp,_file* bf, bool print){
249
_i64tot(bp->initnumber,ttmp,10);
250
STRCPY_TtoA(atmp,ttmp,100);
254
sb.append("(obj). ");
258
sb.append(bf->value);
259
sb.append(", line ");
261
_i64tot(bp->initline,ttmp,10);
262
STRCPY_TtoA(atmp,ttmp,100);
267
if ( print && sb.length() > 0 ){
268
printf("%s\n", sb.c_str());
272
char* __internalcl_GetUnclosedObjects(bool print){
275
SCOPED_LOCK_MUTEX(memleak_lock)
278
bool unknowns = false;
279
if ( LuceneBase_Pointers.size() > 0 ){
281
_i64tot(LuceneBase_Pointers.size(),ttmp,10);
282
STRCPY_TtoA(atmp,ttmp,100);
285
sb.append(" clucene objects are still open\n");
287
defPointer::iterator itr = LuceneBase_Pointers.begin();
288
while ( itr != LuceneBase_Pointers.end() ){
289
_pointers* bp = itr->second;
290
_file* bf = bp->file;
292
if ( bp->initline == -1 )
294
__internalcl_PrintUnclosedObject(true, sb,bp,bf,print);
299
defVoid::iterator itr2 = LuceneBase_Voids.begin();
300
while ( itr2 != LuceneBase_Voids.end() ){
301
_pointers* bp = itr2->second;
302
_file* bf = bp->file;
304
if ( bp->initline == -1 )
306
__internalcl_PrintUnclosedObject(false, sb,bp,bf,print);
312
if ( unknowns == true ){
313
sb.append("*** Some memory was not created with _CLNEW and was not tracked... ***\n");
314
sb.append("*** Use _CLNEW instead of new when creating CLucene objects ***\n");
315
sb.append("*** Memory may also have not been freed in the current context ***\n");
319
if ( sb.length() > 0 ){
320
printf("%s\n", sb.c_str());
325
if ( sb.length() > 0 )
326
return STRDUP_AtoA(sb.c_str());
332
void LuceneBase::__cl_ClearMemory(){
333
SCOPED_LOCK_MUTEX(memleak_lock)
335
while ( LuceneBase_Files.size() > 0 ){
336
defFile::iterator fi = LuceneBase_Files.begin();
337
_file* f = fi->second;
339
LuceneBase_Files.removeitr (fi);
341
LuceneBase_Pointers.clear();
342
LuceneBase_Voids.clear();
344
char* LuceneBase::__cl_GetUnclosedObjects(){
345
return __internalcl_GetUnclosedObjects(false);
348
int32_t LuceneBase::__cl_GetUnclosedObjectsCount(){
349
return LuceneBase_Pointers.size();
352
const char* LuceneBase::__cl_GetUnclosedObject(int32_t item){
353
SCOPED_LOCK_MUTEX(memleak_lock)
355
defPointer::iterator itr=LuceneBase_Pointers.begin();
357
for ( ;itr!=LuceneBase_Pointers.end() && i<item ;itr++ ){
360
if ( itr != LuceneBase_Pointers.end() )
361
return itr->second->file->value;
365
void LuceneBase::__cl_PrintUnclosedObjects(){
366
__internalcl_GetUnclosedObjects(true);
368
////////////////////////////////////////////////////////////
370
#endif //LUCENE_ENABLE_MEMLEAKTRACKING