Added base library with scl_memmgr implementation.

* scl_memmgr supports both c and c++ memory management.
  malloc, calloc, realloc and free for c.
  new, delete operators for c++.
  (in c++ files scl_memmgr.h should be included last because a macro
   is used to replace new and delete with scl versions. If not included
   last, this would break build.)
This commit is contained in:
davyw
2012-02-27 21:20:15 +01:00
parent 4d68ec0b19
commit 82c84e7337
5 changed files with 515 additions and 0 deletions
+1
View File
@@ -258,6 +258,7 @@ include_directories(
${SCL_BINARY_DIR}/include
)
ADD_SUBDIRECTORY(src/base)
ADD_SUBDIRECTORY(src/express)
ADD_SUBDIRECTORY(src/exppp)
ADD_SUBDIRECTORY(src/fedex_plus)
+13
View File
@@ -1,6 +1,19 @@
#ifndef SCL_EXPORT_H
#define SCL_EXPORT_H
/* Import/Export flags for base. */
#ifndef SCL_BASE_EXPORT
# if defined(SCL_BASE_DLL_EXPORTS) && defined(SCL_BASE_DLL_IMPORTS)
# error "Only SCL_BASE_DLL_EXPORTS or SCL_BASE_DLL_IMPORTS can be defined, not both."
# elif defined(SCL_BASE_DLL_EXPORTS)
# define SCL_BASE_EXPORT __declspec(dllexport)
# elif defined(SCL_BASE_DLL_IMPORTS)
# define SCL_BASE_EXPORT __declspec(dllimport)
# else
# define SCL_BASE_EXPORT
# endif
#endif
/* Import/Export flags for express. */
#ifndef SCL_EXPRESS_EXPORT
# if defined(SCL_EXPRESS_DLL_EXPORTS) && defined(SCL_EXPRESS_DLL_IMPORTS)
+20
View File
@@ -0,0 +1,20 @@
set(SCL_BASE_SOURCES
scl_memmgr.cc
)
include_directories(
${SCL_SOURCE_DIR}/include
)
option(SCL_MEMMGR_ENABLE_CHECKS "Enable scl_memmgr's memory leak detection" OFF)
if(MSVC OR BORLAND)
add_definitions( -DSCL_BASE_DLL_EXPORTS )
endif()
if (${SCL_MEMMGR_ENABLE_CHECKS})
add_definitions( -DSCL_MEMMGR_ENABLE_CHECKS )
endif()
SCL_ADDLIB(base "${SCL_BASE_SOURCES}" "")
+401
View File
@@ -0,0 +1,401 @@
#define SCL_MEMMGR_CC
#include "scl_memmgr.h"
#include <malloc.h>
#include <stdio.h>
#include <string>
#include <set>
#ifdef SCL_MEMMGR_ENABLE_CHECKS
/**
scl_memmgr_error definition
*/
class scl_memmgr_error {
private:
std::string _srcfile;
unsigned int _srcline;
unsigned int _occurences;
public:
scl_memmgr_error( const std::string &file, const unsigned int line );
scl_memmgr_error( const scl_memmgr_error &rhs );
~scl_memmgr_error( void );
bool operator<( const scl_memmgr_error &rhs ) const;
std::string getsrcfile( void ) const;
unsigned int getsrcline( void ) const;
unsigned int getoccurences( void ) const;
};
typedef std::set<scl_memmgr_error> scl_memmgr_errors;
typedef std::set<scl_memmgr_error>::iterator scl_memmgr_error_iterator;
/**
scl_memmgr_record definition
*/
class scl_memmgr_record {
private:
void * _addr;
size_t _size;
std::string _srcfile;
unsigned int _srcline;
public:
scl_memmgr_record( void * addr, size_t size, const char *file, const unsigned int line );
scl_memmgr_record( void * addr );
scl_memmgr_record( const scl_memmgr_record &rhs );
~scl_memmgr_record( void );
bool operator<( const scl_memmgr_record &rhs ) const;
void * getaddr( void ) const;
size_t getsize( void ) const;
std::string getsrcfile( void ) const;
unsigned int getsrcline( void ) const;
};
typedef std::set<scl_memmgr_record> scl_memmgr_records;
typedef std::set<scl_memmgr_record>::iterator scl_memmgr_record_iterator;
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
/**
scl_memmgr definition
*/
class scl_memmgr {
private:
#ifdef SCL_MEMMGR_ENABLE_CHECKS
bool _record_insert_busy, _record_erase_busy;
// memory allocation/reallocation records, inserted at allocation, erased at deallocation.
scl_memmgr_records _records;
// memory stats
unsigned int _allocated; // amount of memory allocated simultaniously
unsigned int _maximum_allocated; // maximum amount of memory allocated simultaniously
unsigned int _allocated_total; // total amount of memory allocated in bytes
unsigned int _reallocated_total; // total amount of memory reallocated in bytes
unsigned int _deallocated_total; // total amount of memory deallocated in bytes
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
protected:
public:
scl_memmgr(void);
~scl_memmgr(void);
void * allocate( size_t size, const char *file, const int line );
void * reallocate( void * addr, size_t size, const char *file, const int line );
void deallocate( void * addr, const char *file, const int line );
};
/**
scl_memmgr instance.
There should be one static instance of memmgr.
This instance is automatically destroyed when application exits, so this allows us to add
memory leak detection in it's destructor.
*/
scl_memmgr memmgr;
/**
c memory functions implementation
*/
extern "C" {
void * scl_malloc_fn( unsigned int size, const char * file, const int line ) {
return memmgr.allocate(size, file, line);
}
void * scl_calloc_fn( unsigned int count, unsigned int size, const char * file, const int line ) {
return memmgr.allocate(count * size, file, line);
}
void * scl_realloc_fn( void * addr, unsigned int size, const char * file, const int line ) {
return memmgr.reallocate(addr, size, file, line);
}
void scl_free_fn( void * addr ) {
memmgr.deallocate(addr, "", 0);
}
}
/**
c++ memory operators implementation
*/
void * scl_operator_new( size_t size, const char * file, const int line ) {
return memmgr.allocate(size, file, line);
}
void scl_operator_delete( void * addr, const char * file, const int line ) {
memmgr.deallocate(addr, file, line);
}
void scl_operator_delete( void * addr ) {
memmgr.deallocate(addr, "", 0);
}
/**
scl_memmgr implementation
*/
scl_memmgr::scl_memmgr(void) {
#ifdef SCL_MEMMGR_ENABLE_CHECKS
_record_insert_busy = false;
_record_erase_busy = false;
_allocated = 0;
_maximum_allocated = 0;
_allocated_total = 0;
_reallocated_total = 0;
_deallocated_total = 0;
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
}
/**
Destructor:
scl_memmgr::~scl_memmgr(void)
Description:
The scl_memmgr destructor is used to check for memory leaks when enabled.
All records still present when scl_memmgr instance is destroyed can be considered as
memory leaks.
*/
scl_memmgr::~scl_memmgr(void) {
#ifdef SCL_MEMMGR_ENABLE_CHECKS
scl_memmgr_record_iterator irecord;
scl_memmgr_errors errors;
scl_memmgr_error_iterator ierror;
// Check if total allocated equals total deallocated
if (_allocated_total != _deallocated_total) {
// todo: generate warning for possible memory leaks, enable full memory leak checking
printf("scl_memmgr warning: Possible memory leaks detected\n");
}
// Compact leaks into an error list to prevent same leak being reported multiple times.
_record_insert_busy = true;
_record_erase_busy = true;
for (irecord = _records.begin();
irecord != _records.end();
irecord ++) {
scl_memmgr_error error(irecord->getsrcfile(), irecord->getsrcline());
ierror = errors.find(error);
if (ierror == errors.end())
errors.insert(error);
//else
// ierror->occurences ++;
}
_record_insert_busy = false;
_record_erase_busy = false;
// Loop through memory leaks to generate/buffer errors
for (ierror = errors.begin();
ierror != errors.end();
ierror ++) {
// todo: generate error for memory leak
printf("scl_memmgr warning: Possible memory leak in %s line %d\n", ierror->getsrcfile().c_str(), ierror->getsrcline());
}
// Clear remaining records
_record_erase_busy = true;
_records.clear();
errors.clear();
_record_erase_busy = false;
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
}
void * scl_memmgr::allocate( size_t size, const char *file, const int line ) {
void * addr;
// Allocate
addr = malloc(size);
if (addr == NULL) {
// todo: error allocation failed
printf("scl_memmgr error: Memory allocation failed in %s line %d\n", file, line);
}
// Some stl implementations (for example debian gcc) use the new operator to construct
// new elements when inserting scl_memmgr_record. When this our new operator gets used
// for this operation, this would result in an infinite loop. This is fixed by the
// _record_insert_busy flag.
#ifdef SCL_MEMMGR_ENABLE_CHECKS
if (!_record_insert_busy)
{
// Store record for this allocation
_record_insert_busy = true;
_records.insert(scl_memmgr_record(addr, size, file, line));
_record_insert_busy = false;
// Update stats
_allocated += size;
if (_allocated > _maximum_allocated)
_maximum_allocated = _allocated;
_allocated_total += size;
}
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
return addr;
}
void * scl_memmgr::reallocate( void * addr, size_t size, const char *file, const int line ) {
#ifdef SCL_MEMMGR_ENABLE_CHECKS
scl_memmgr_record_iterator record;
if (!_record_insert_busy)
{
// Find record of previous allocation/reallocation
record = _records.find(scl_memmgr_record(addr));
if (record == _records.end()) {
// todo: error reallocating memory not allocated?
printf("scl_memmgr warning: Reallocation of not allocated memory at %s line %d\n", file, line);
}
else {
// Update stats
_allocated -= record->getsize();
_deallocated_total += record->getsize();
// Erase previous allocation/reallocation
_record_erase_busy = true;
_records.erase(record);
_record_erase_busy = false;
}
}
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
// Reallocate
addr = realloc(addr, size);
if (addr == NULL) {
// todo: error reallocation failed
printf("scl_memmgr error: Reallocation failed at %s line %d\n", file, line);
}
#ifdef SCL_MEMMGR_ENABLE_CHECKS
if (!_record_insert_busy)
{
// Store record for this reallocation
_record_insert_busy = true;
_records.insert(scl_memmgr_record(addr, size, file, line));
_record_insert_busy = false;
// Update stats
_allocated += size;
if (_allocated > _maximum_allocated)
_maximum_allocated = _allocated;
_allocated_total += size;
_reallocated_total += size;
}
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
return addr;
}
void scl_memmgr::deallocate( void * addr, const char *file, const int line ) {
#ifdef SCL_MEMMGR_ENABLE_CHECKS
scl_memmgr_record_iterator record;
if (!_record_erase_busy)
{
// Find record of previous allocation/reallocation
record = _records.find(scl_memmgr_record(addr));
if (record == _records.end()) {
// todo: error free called for not allocated memory?
printf("scl_memmgr warning: Deallocate of not allocated memory at %s line %d\n", file, line);
}
else {
// Update stats
_allocated -= record->getsize();
_deallocated_total += record->getsize();
// Erase record
_record_erase_busy = true;
_records.erase(record);
_record_erase_busy = false;
}
}
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
// Deallocate
free(addr);
}
#ifdef SCL_MEMMGR_ENABLE_CHECKS
/**
scl_memmgr_error implementation
*/
scl_memmgr_error::scl_memmgr_error( const std::string &file, const unsigned int line ) {
_srcfile = file;
_srcline = line;
_occurences = 1;
}
scl_memmgr_error::scl_memmgr_error( const scl_memmgr_error &rhs ) {
_srcfile = rhs._srcfile;
_srcline = rhs._srcline;
_occurences = rhs._occurences;
}
scl_memmgr_error::~scl_memmgr_error( void ) {
}
bool scl_memmgr_error::operator<( const scl_memmgr_error &rhs ) const {
if (_srcfile == rhs._srcfile)
return _srcline < rhs._srcline;
return _srcfile < rhs._srcfile;
}
std::string scl_memmgr_error::getsrcfile( void ) const {
return _srcfile;
}
unsigned int scl_memmgr_error::getsrcline( void ) const {
return _srcline;
}
unsigned int scl_memmgr_error::getoccurences( void ) const {
return _occurences;
}
/**
scl_memmgr_record implementation
*/
scl_memmgr_record::scl_memmgr_record( void * addr, size_t size, const char *file, const unsigned int line ) {
_addr = addr;
_size = size;
_srcfile = file;
_srcline = line;
}
scl_memmgr_record::scl_memmgr_record( void * addr ) {
_addr = addr;
_size = 0;
_srcfile = "";
_srcline = -1;
}
scl_memmgr_record::scl_memmgr_record( const scl_memmgr_record &rhs ) {
_addr = rhs._addr;
_size = rhs._size;
_srcfile = rhs._srcfile;
_srcline = rhs._srcline;
}
scl_memmgr_record::~scl_memmgr_record( void ) {
}
bool scl_memmgr_record::operator<( const scl_memmgr_record &rhs ) const {
return _addr < rhs._addr;
}
void * scl_memmgr_record::getaddr( void ) const {
return _addr;
}
size_t scl_memmgr_record::getsize( void ) const {
return _size;
}
std::string scl_memmgr_record::getsrcfile( void ) const {
return _srcfile;
}
unsigned int scl_memmgr_record::getsrcline( void ) const {
return _srcline;
}
#endif /* SCL_MEMMGR_ENABLE_CHECKS */
+80
View File
@@ -0,0 +1,80 @@
#ifndef SCL_MEMMGR_H
#define SCL_MEMMGR_H
#include <scl_export.h>
/**
Platform specific defines
*/
#if defined(__MSVC__) || defined(__BORLAND__)
#define THROW_STD_BAD_ALLOC
#define THROW_EMPTY
#else
#define THROW_STD_BAD_ALLOC throw (std::bad_alloc)
#define THROW_EMPTY throw ()
#endif
#ifdef __cplusplus
#include <cstddef>
extern "C" {
#endif /* __cplusplus */
SCL_BASE_EXPORT void * scl_malloc_fn( unsigned int size, const char *file, const int line );
SCL_BASE_EXPORT void * scl_calloc_fn( unsigned int count, unsigned int size, const char *file, const int line );
SCL_BASE_EXPORT void * scl_realloc_fn( void * addr, unsigned int size, const char *file, const int line );
SCL_BASE_EXPORT void scl_free_fn( void * addr );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#ifdef __cplusplus
SCL_BASE_EXPORT void * scl_operator_new( size_t size, const char * file, const int line );
SCL_BASE_EXPORT void scl_operator_delete( void * addr, const char *file, const int line );
SCL_BASE_EXPORT void scl_operator_delete( void * addr );
#endif /* __cplusplus */
#ifndef SCL_MEMMGR_CC
#define scl_malloc(size) scl_malloc_fn(size, __FILE__, __LINE__)
#define scl_calloc(count, size) scl_calloc_fn(count, size, __FILE__, __LINE__)
#define scl_realloc(addr, size) scl_realloc_fn(addr, size, __FILE__, __LINE__)
#define scl_free(addr) scl_free_fn(addr)
#ifdef __cplusplus
#include <new>
inline void * operator new( size_t size, const char *file, const int line ) THROW_STD_BAD_ALLOC {
return scl_operator_new(size, file, line);
}
inline void * operator new[]( size_t size, const char *file, const int line ) THROW_STD_BAD_ALLOC {
return scl_operator_new(size, file, line);
}
inline void operator delete( void *addr, const char *file, const int line ) THROW_STD_BAD_ALLOC {
scl_operator_delete(addr, file, line);
}
inline void operator delete[]( void *addr, const char *file, const int line ) THROW_STD_BAD_ALLOC {
scl_operator_delete(addr, file, line);
}
inline void operator delete( void * addr ) THROW_EMPTY {
scl_operator_delete(addr);
}
inline void operator delete[]( void * addr ) THROW_EMPTY {
scl_operator_delete(addr);
}
#define new new(__FILE__, __LINE__)
#endif /* __cplusplus */
#endif /* SCL_MEMMGR_CC */
#endif /* SCL_MEMMGR_H */