mksqlite  2.5
A MATLAB interface to SQLite
heap_check.hpp
Go to the documentation of this file.
1 
18 #ifndef HEAP_CHECK_HPP
19 #define HEAP_CHECK_HPP
20 
21 #include <vector>
22 
23 #define HC_ASSERT_ERROR _HC_DoAssert(__FILE__,__FUNCTION__,__LINE__)
24 #define HC_ASSERT(exp) if (!(exp)) {HC_ASSERT_ERROR;} else
25 #define HC_NOTES(ptr,notes) HeapCheck.UpdateNotes(ptr,notes)
27 #define HC_COMP_ASSERT(exp) extern char _HC_CompAssert[(exp)?1:-1]
29 
30 #define HC_ABS(x) (((x)>0)?(x):-(x))
31 #define HC_ISPOWER2(x) (!((x)&((x)-1)))
32 #define HC_ALIGNMENT (sizeof(int))
33 #define HC_DOALIGN(num) (((num)+HC_ALIGNMENT-1)&~(HC_ALIGNMENT-1))
34 
35 
37 #define USE_HC_ASSERT \
38 extern "C" void HC_ReportAssert ( const char*, const char*, long ); \
39 static int _HC_DoAssert ( const char* file, const char* func, int nLine ) \
40 { \
41  HC_ReportAssert(file, func, nLine); \
42  HC_ASSERT(nLine); /* inhibit removal of unreferenced function */ \
43  return(0); \
44 }
45 
49 
50 
52 class HeapCheck
53 {
54  struct tagFooter; // forward declaration
55 
66  struct tagHeader
67  {
69  const char* lpFilename;
70  const char* lpFunctionName;
71  long lLineNumber;
72  void* lpMem;
73  const char* lpNotes;
74  };
75 
82  struct tagFooter
83  {
85  };
86 
88  typedef std::vector<const tagHeader*> vec_tagHeader;
89 
91  vec_tagHeader m_mem_blocks;
92 
95 
96 public:
97 
103  {
104  flag_blocks_checked = false;
105  }
106 
114  {
115  Release();
116  }
117 
118 
127  void Release()
128  {
129  int count = 0;
130 
131  Walk();
132 
133  for( int i = 0; i < (int)m_mem_blocks.size(); i++ )
134  {
135  if( m_mem_blocks[i] != NULL )
136  {
137  MEM_FREE( m_mem_blocks[i] );
138  m_mem_blocks[i] = NULL;
139  count++;
140  }
141  }
142 
143  m_mem_blocks.clear();
144 
145 #if defined(MATLAB_MEX_FILE) /* MATLAB MEX file */
146  if( !count && !flag_blocks_checked )
147  {
148  PRINTF( "Heap check: ok\n" );
149  }
150 #endif
151  flag_blocks_checked = true;
152  }
153 
154 
156  static
157  size_t GetHeaderSize()
158  {
159  return sizeof( tagHeader );
160  }
161 
162 
169  static
170  int isPtrAligned( const void* ptr )
171  {
172  return ( (ptr) && (!( (long)ptr & (HC_ALIGNMENT-1) )) );
173  }
174 
175 
182  static
183  int VerifyPtr( const void* ptr )
184  {
185  int bOk = 0;
186 
187  if( ptr )
188  {
189  HC_ASSERT( isPtrAligned(ptr) )
190  {
191  tagHeader* header = (tagHeader*)ptr - 1;
192  HC_ASSERT( header->lpMem == ptr )
193  {
194  HC_ASSERT( header->lpFooter->lpHeader == header )
195  {
196  bOk = 1;
197  }
198  }
199  }
200  }
201 
202  return bOk;
203  }
204 
205 
207  void AddPtr( const tagHeader* ptr )
208  {
209  m_mem_blocks.push_back( ptr );
210  flag_blocks_checked = false;
211  }
212 
213 
215  void RemovePtr( const tagHeader* ptr )
216  {
218  for( int i = 0; i < (int)m_mem_blocks.size(); i++ )
219  {
220  if( m_mem_blocks[i] == ptr )
221  {
222  m_mem_blocks.erase( m_mem_blocks.begin() + i );
223  break;
224  }
225  }
226  }
227 
228 
239  void* New( size_t bytes, const char* file, const char* fcn, const char* notes, long nLine )
240  {
241  tagHeader* mem_block = NULL;
242  size_t bytes_aligned = HC_DOALIGN( bytes );
243 
244  // Allocate memory with additional space for header and footer
245  mem_block = (tagHeader*)MEM_CALLOC( bytes_aligned + sizeof(tagHeader) + sizeof(tagFooter), 1 );
246 
247  if( mem_block != NULL )
248  {
249  mem_block->lpFooter = (tagFooter*)((char*)(mem_block + 1) + bytes_aligned);
250  mem_block->lpFooter->lpHeader = mem_block; // do link
251  mem_block->lpMem = mem_block + 1; // point to users memory block
252  mem_block->lpFilename = file;
253  mem_block->lpFunctionName = fcn;
254  mem_block->lpNotes = notes;
255  mem_block->lLineNumber = nLine;
256 
257  memset( mem_block->lpMem, 0, bytes_aligned ); // zero init
258 
259  AddPtr( mem_block ); // Enqueue
260  }
261  else
262  {
263  HC_ASSERT_ERROR;
264  }
265 
266 
267  return mem_block ? (mem_block + 1) : NULL;
268  }
269 
270 
282  void* Realloc( void* ptr_old, size_t bytes,
283  const char* file, const char* fcn, const char* notes, long nLine )
284  {
285  void* ptr_new = NULL;
286  size_t bytes_aligned = HC_DOALIGN(bytes);
287 
288  // Try to reallocate previously allocated space
289  if( ptr_old )
290  {
291  if( VerifyPtr(ptr_old) )
292  {
293  tagHeader* header = (tagHeader*)ptr_old - 1;
294  tagHeader* header_new = NULL;
295  tagHeader* header_ins = NULL;
296 
297  // Try to reallocate block
298  RemovePtr( header );
299  memset( header->lpFooter, 0, sizeof(tagFooter) );
300  header_new = (tagHeader*)MEM_REALLOC( header, sizeof(tagHeader) + bytes_aligned + sizeof(tagFooter) );
301 
302  // Add new (or failed old) back in
303  header_ins = header_new ? header_new : header;
304  header_ins->lpFooter = (tagFooter*)( (char*)(header_ins+1) + bytes_aligned );
305  header_ins->lpFooter->lpHeader = header_ins;
306  header_ins->lpMem = header_ins + 1;
307  header_ins->lpFilename = file ? file : header_ins->lpFilename;
308  header_ins->lpFunctionName = fcn ? fcn : header_ins->lpFunctionName;
309  header_ins->lpNotes = notes ? notes : header_ins->lpNotes;
310  header_ins->lLineNumber = nLine ? nLine : header_ins->lLineNumber;
311 
312  AddPtr( header_ins );
313 
314 
315  // Finish
316  ptr_new = header_new ? (header_new + 1) : NULL;
317 
318  if( !ptr_new )
319  {
320  // Report out of memory error
321  HC_ASSERT_ERROR;
322  }
323  }
324  }
325  else
326  {
327  // Pointer was NULL, do a normal allocation
328  ptr_new = New( bytes_aligned, file, fcn, notes, nLine );
329  }
330 
331  // Return address to object
332  return ptr_new;
333  }
334 
335 
337  void Free( void* ptr )
338  {
339  if( VerifyPtr(ptr) )
340  {
341  tagHeader* header = (tagHeader*)ptr - 1;
342  size_t bytes_aligned = (char*)(header->lpFooter+1) - (char*)header;
343 
344  RemovePtr( header ); // dequeue
345  memset( header, 0, sizeof(tagHeader) ); // set to zero
346  MEM_FREE( header ); // and free
347  }
348  }
349 
350 
352  void UpdateNotes( void* ptr, const char* notes )
353  {
354  if( VerifyPtr(ptr) )
355  {
356  tagHeader* header = (tagHeader*)ptr - 1;
357 
358  header->lpNotes = notes;
359  }
360  }
361 
362 
370  static
371  void RenderDesc( const tagHeader* header, char* lpBuffer, size_t szBuffer )
372  {
373  memset( lpBuffer, 0, szBuffer );
374  int left;
375 
376  if( header->lpMem == &header[1] )
377  {
378  _snprintf( lpBuffer, szBuffer, "%08lx ", (long unsigned)header );
379 
380  if( header->lpFilename && (left = (int)szBuffer - (int)strlen(lpBuffer)) > 1 )
381  {
382  _snprintf( lpBuffer + strlen(lpBuffer), left, "%12s %4ld ",
383  header->lpFilename, header->lLineNumber );
384  }
385  if( header->lpFunctionName && (left = (int)szBuffer - (int)strlen(lpBuffer)) > 1 )
386  {
387  _snprintf( lpBuffer + strlen(lpBuffer), left, " (%s)",
388  header->lpFunctionName );
389  }
390  if( header->lpNotes && (left = (int)szBuffer - (int)strlen(lpBuffer)) > 1 )
391  {
392  _snprintf( lpBuffer + strlen(lpBuffer), left, " %s",
393  header->lpNotes );
394  }
395  } else {
396  _snprintf( lpBuffer, szBuffer, "(bad)" );
397  }
398 
399  }
400 
401 
407  void Walk( const char* text = NULL )
408  {
409  for( int i = 0; i < (int)m_mem_blocks.size(); i++ )
410  {
411  char buffer[1024];
412 
413  RenderDesc( m_mem_blocks[i], buffer, 1024 );
414 
415 #if defined(MATLAB_MEX_FILE) /* MATLAB MEX file */
416 
417  /*--- print out buffer ---*/
418  if( text )
419  {
420  PRINTF( "walk(%s): %s\n", text, buffer );
421  } else {
422  PRINTF( "walk: %s\n", buffer );
423  }
424 #endif
425  }
426  }
427 };
428 
429 
431 #if defined( MAIN_MODULE )
432 
440  extern "C"
441  void HC_ReportAssert( const char* file, const char* lpFunctionName, long line )
442  {
443  char buffer[1024];
444 
445  _snprintf( buffer, 1024, "Assertion failed in %s, %s line %ld\n", file, lpFunctionName, line );
446 
447  #if defined(MATLAB_MEX_FILE) /* MATLAB MEX file */
448  mxAssert( 0, buffer );
449  #else
450  assert( false );
451  #endif
452  }
453 
456 #else
457  extern class HeapCheck HeapCheck;
459 #endif
460 
461 
462 // Guaranteeing correct prefix structure alignment
467 
468 #endif // HEAP_CHECK_HPP
469 
void Free(void *ptr)
Freeing space returned from New() or Realloc()
Definition: heap_check.hpp:337
#define HC_ASSERT(exp)
Definition: heap_check.hpp:24
#define HC_DOALIGN(num)
memory alignment
Definition: heap_check.hpp:33
void * New(size_t bytes, const char *file, const char *fcn, const char *notes, long nLine)
Allocates a new block of memory with initialized header and footer.
Definition: heap_check.hpp:239
void Release()
Releasing unfreed memory.
Definition: heap_check.hpp:127
static int VerifyPtr(const void *ptr)
Checks if header pointer ptr is valid.
Definition: heap_check.hpp:183
static int isPtrAligned(const void *ptr)
Checks if header pointer ptr is well aligned.
Definition: heap_check.hpp:170
tagFooter * lpFooter
pointer to footer, contiguous to memory block
Definition: heap_check.hpp:68
void HC_ReportAssert(const char *file, const char *lpFunctionName, long line)
Standard assert routine used by macro HC_ASSERT.
Definition: heap_check.hpp:441
const char * lpFilename
filename or NULL
Definition: heap_check.hpp:69
static size_t GetHeaderSize()
Returns the header size in bytes.
Definition: heap_check.hpp:157
static void RenderDesc(const tagHeader *header, char *lpBuffer, size_t szBuffer)
Formatted output of memory block information (from its header)
Definition: heap_check.hpp:371
#define HC_ALIGNMENT
align to integer
Definition: heap_check.hpp:32
void AddPtr(const tagHeader *ptr)
Enqueues new memory block by header pointer ptr.
Definition: heap_check.hpp:207
bool flag_blocks_checked
Flag will be set, when the block m_mem_blocks is released and checked.
Definition: heap_check.hpp:94
void * lpMem
pointer to memory block (contiguous to this header space)
Definition: heap_check.hpp:72
~HeapCheck()
Destructor.
Definition: heap_check.hpp:113
Memory block header.
Definition: heap_check.hpp:66
#define MEM_FREE(ptr)
standard memory free function
Definition: global.hpp:158
std::vector< const tagHeader * > vec_tagHeader
Memory blocks linked list typedef.
Definition: heap_check.hpp:88
void RemovePtr(const tagHeader *ptr)
Removes memory block, identified by ptr without freeing it.
Definition: heap_check.hpp:215
#define MEM_REALLOC(ptr, size)
standard memory deallocator
Definition: global.hpp:157
void * Realloc(void *ptr_old, size_t bytes, const char *file, const char *fcn, const char *notes, long nLine)
Reallocates a block of memory allocated with New()
Definition: heap_check.hpp:282
long lLineNumber
line number or 0
Definition: heap_check.hpp:71
const char * lpNotes
pointer to further notes or NULL
Definition: heap_check.hpp:73
#define USE_HC_ASSERT
Macro USE_HC_ASSERT must exist in every module which uses macro HC_ASSERT.
Definition: heap_check.hpp:37
tagHeader * lpHeader
pointer to header of this memory block
Definition: heap_check.hpp:84
Helperclass for memory leak and access violation detection.
Definition: heap_check.hpp:52
void Walk(const char *text=NULL)
Reporting walk through the linked memory list.
Definition: heap_check.hpp:407
#define HC_ISPOWER2(x)
check if is a power of 2
Definition: heap_check.hpp:31
HeapCheck()
Standard ctor.
Definition: heap_check.hpp:102
vec_tagHeader m_mem_blocks
Linked list of memory blocks used in module scope.
Definition: heap_check.hpp:91
const char * lpFunctionName
function name
Definition: heap_check.hpp:70
#define HC_COMP_ASSERT(exp)
Verifies design-time assumptions (exp) at compile-time.
Definition: heap_check.hpp:28
#define PRINTF
Global text output function.
Definition: global.hpp:230
void UpdateNotes(void *ptr, const char *notes)
Update "notes" field in memory block header.
Definition: heap_check.hpp:352