123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /*
- * DUMA - Red-Zone memory allocator.
- * Copyright (C) 2020-2022 Jeffrey H. Johnson <trnsz@pobox.com>
- * Copyright (C) 2006 Michael Eddington <meddington@gmail.com>
- * Copyright (C) 2002-2021 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
- * Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
- * License: GNU GPL (GNU General Public License, see COPYING-GPL)
- *
- * This program 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.
- *
- * This program 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 this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
- * FILE CONTENTS:
- * header file for inclusion from YOUR application code
- */
- /* explicitly no "#ifndef _DUMA_H_" to allow mutliple inclusions
- * within single source file with inclusion of noduma.h in between
- */
- #include <stdlib.h>
- /*
- * #include <stdlib.h>
- *
- * You must include <stdlib.h> before including <duma.h> !
- *
- */
- /* for enabling inclusion of duma.h after inclusion of efencint.h */
- /* remove previous definitions */
- #define SKIP_DUMA_NO_CXX
- #include "noduma.h"
- #undef SKIP_DUMA_NO_CXX
- #include "duma_config.h"
- #ifdef __cplusplus
- #define DUMA_EXTERN_C extern "C"
- #else
- #define DUMA_EXTERN_C extern
- #endif
- #ifdef DUMA_NO_DUMA
- /* enable these macros even in release code, but do nothing */
- #define DUMA_newFrame() \
- do { \
- } while (0)
- #define DUMA_delFrame() \
- do { \
- } while (0)
- #define DUMA_SET_ALIGNMENT(V) \
- do { \
- } while (0)
- #define DUMA_SET_PROTECT_BELOW(V) \
- do { \
- } while (0)
- #define DUMA_SET_FILL(V) \
- do { \
- } while (0)
- #define DUMA_ASSERT(EXPR) \
- do { \
- } while (0)
- #define DUMA_CHECK(BASEADR) \
- do { \
- } while (0)
- #define DUMA_CHECKALL() \
- do { \
- } while (0)
- #define CA_DECLARE(NAME, SIZE) \
- do { \
- } while (0)
- #define CA_DEFINE(TYPE, NAME, SIZE) TYPE NAME[SIZE]
- #define CA_REF(NAME, INDEX) NAME[INDEX]
- #else /* ifndef DUMA_NO_DUMA */
- #ifndef DUMA_EXTERNS_DECLARED
- #define DUMA_EXTERNS_DECLARED
- /* global DUMA variables */
- DUMA_EXTERN_C int DUMA_OUTPUT_DEBUG;
- DUMA_EXTERN_C int DUMA_OUTPUT_STDOUT;
- DUMA_EXTERN_C int DUMA_OUTPUT_STDERR;
- DUMA_EXTERN_C char *DUMA_OUTPUT_FILE;
- DUMA_EXTERN_C int DUMA_OUTPUT_STACKTRACE;
- #endif /* DUMA_EXTERNS_DECLARED */
- /* set Maximum Delete Depth (depth of recursive destructor calls) */
- #ifndef DUMA_MAX_DEL_DEPTH
- #define DUMA_MAX_DEL_DEPTH 256
- #endif
- #ifndef DUMA_TLSVARTYPE_DEFINED
- #define DUMA_TLSVARTYPE_DEFINED
- /* GitHub #82 - following variables should exist per thread ("thread-local") */
- typedef struct {
- /*
- * ALIGNMENT is a global variable used to control the default alignment
- * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
- * so that its name matches the name of the environment variable that is used
- * to set it. This gives the programmer one less name to remember.
- */
- int ALIGNMENT;
- /*
- * PROTECT_BELOW is used to modify the behavior of the allocator. When
- * its value is non-zero, the allocator will place an inaccessable page
- * immediately _before_ the malloc buffer in the address space, instead
- * of _after_ it. Use this to detect malloc buffer under-runs, rather than
- * over-runs. It won't detect both at the same time, so you should test your
- * software twice, once with this value clear, and once with it set.
- */
- int PROTECT_BELOW;
- /*
- * FILL is set to 0-255 if DUMA should fill all new allocated
- * memory with the specified value. Set to -1 when DUMA should not
- * initialise allocated memory.
- * default is set to initialise with 255, cause many programs rely on
- * initialisation to 0!
- */
- int FILL;
- #if !defined(DUMA_NO_CPP_SUPPORT) && !defined(DUMA_NO_LEAKDETECTION)
- int Magic;
- int DelPtr;
- const char *DelFile[DUMA_MAX_DEL_DEPTH];
- int DelLine[DUMA_MAX_DEL_DEPTH];
- #endif
- } DUMA_TLSVARS_T;
- #endif
- #ifndef DUMA_GLOBALS_DEFINED
- #define DUMA_GLOBALS_DEFINED
- typedef struct {
- /* Protection Space A */
- char acSpaceA[2 * DUMA_PAGE_SIZE];
- /* Variable: _duma_allocList
- *
- * _DUMA_allocList points to the array of slot structures used to manage the
- * malloc arena.
- */
- struct _DUMA_Slot *allocList;
- /* Variable: _duma_null_addr
- *
- * _duma_null_addr is the address malloc() or C++ operator new returns, when
- * size is 0 two pages get reserved and protected
- */
- void *null_addr;
- /* Variable */
- DUMA_TLSVARS_T TLS;
- /* Protection Space B */
- char acSpaceB[2 * DUMA_PAGE_SIZE];
- } DUMA_GLOBALVARS_T;
- DUMA_EXTERN_C DUMA_GLOBALVARS_T _duma_g;
- #endif /* DUMA_GLOBALS_DEFINED */
- #define GET_DUMA_TLSVARS() (&_duma_g.TLS)
- #ifndef DUMA_SET_ALIGNMENT
- #define DUMA_SET_ALIGNMENT(V) GET_DUMA_TLSVARS()->ALIGNMENT = (V)
- #endif
- #ifndef DUMA_SET_PROTECT_BELOW
- #define DUMA_SET_PROTECT_BELOW(V) GET_DUMA_TLSVARS()->PROTECT_BELOW = (V)
- #endif
- #ifndef DUMA_SET_FILL
- #define DUMA_SET_FILL(V) GET_DUMA_TLSVARS()->FILL = (V)
- #endif
- #ifndef DUMA_ENUMS_DECLARED
- #define DUMA_ENUMS_DECLARED
- /* allocator defines the type of calling allocator/deallocator function */
- enum _DUMA_Allocator {
- EFA_INT_ALLOC,
- EFA_INT_DEALLOC,
- EFA_MALLOC,
- EFA_CALLOC,
- EFA_FREE,
- EFA_MEMALIGN,
- EFA_POSIX_MEMALIGN,
- EFA_REALLOC,
- EFA_VALLOC,
- EFA_STRDUP,
- EFA_NEW_ELEM,
- EFA_DEL_ELEM,
- EFA_NEW_ARRAY,
- EFA_DEL_ARRAY
- /* use following enums when calling _duma_allocate()/_duma_deallocate()
- * from user defined member operators
- */
- ,
- EFA_MEMBER_NEW_ELEM,
- EFA_MEMBER_DEL_ELEM,
- EFA_MEMBER_NEW_ARRAY,
- EFA_MEMBER_DEL_ARRAY
- };
- enum _DUMA_FailReturn { DUMA_FAIL_NULL, DUMA_FAIL_ENV };
- #endif /* DUMA_ENUMS_DECLARED */
- #ifndef DUMA_FUNCTIONS_DECLARED
- #define DUMA_FUNCTIONS_DECLARED
- DUMA_EXTERN_C void _duma_init(void);
- DUMA_EXTERN_C void _duma_assert(const char *exprstr, const char *filename,
- int lineno);
- DUMA_EXTERN_C void duma_check(void *address);
- DUMA_EXTERN_C void duma_checkAll();
- DUMA_EXTERN_C void *duma_alloc_return(void *address);
- #ifdef DUMA_EXPLICIT_INIT
- DUMA_EXTERN_C void duma_init(void);
- #endif
- #ifndef DUMA_NO_LEAKDETECTION
- DUMA_EXTERN_C void *_duma_allocate(size_t alignment, size_t userSize,
- int protectBelow, int fillByte,
- int protectAllocList,
- enum _DUMA_Allocator allocator,
- enum _DUMA_FailReturn fail,
- const char *filename, int lineno);
- DUMA_EXTERN_C void _duma_deallocate(void *baseAdr, int protectAllocList,
- enum _DUMA_Allocator allocator,
- const char *filename, int lineno);
- DUMA_EXTERN_C void *_duma_malloc(size_t size, const char *filename, int lineno);
- DUMA_EXTERN_C void *_duma_calloc(size_t elemCount, size_t elemSize,
- const char *filename, int lineno);
- DUMA_EXTERN_C void _duma_free(void *baseAdr, const char *filename, int lineno);
- DUMA_EXTERN_C void *_duma_memalign(size_t alignment, size_t userSize,
- const char *filename, int lineno);
- DUMA_EXTERN_C int _duma_posix_memalign(void **memptr, size_t alignment,
- size_t userSize, const char *filename,
- int lineno);
- DUMA_EXTERN_C void *_duma_realloc(void *baseAdr, size_t newSize,
- const char *filename, int lineno);
- DUMA_EXTERN_C void *_duma_valloc(size_t size, const char *filename, int lineno);
- DUMA_EXTERN_C size_t _duma_malloc_usable_size(void *ptr, const char *filename,
- int lineno);
- DUMA_EXTERN_C char *_duma_strdup(const char *str, const char *filename,
- int lineno);
- DUMA_EXTERN_C void *_duma_memcpy(void *dest, const void *src, size_t size,
- const char *filename, int lineno);
- DUMA_EXTERN_C void *_duma_memmove(void *dest, const void *src, size_t size);
- DUMA_EXTERN_C char *_duma_strcpy(char *dest, const char *src,
- const char *filename, int lineno);
- DUMA_EXTERN_C char *_duma_strncpy(char *dest, const char *src, size_t size,
- const char *filename, int lineno);
- DUMA_EXTERN_C char *_duma_strcat(char *dest, const char *src,
- const char *filename, int lineno);
- DUMA_EXTERN_C char *_duma_strncat(char *dest, const char *src, size_t size,
- const char *filename, int lineno);
- DUMA_EXTERN_C void DUMA_newFrame(void);
- DUMA_EXTERN_C void DUMA_delFrame(void);
- #else /* DUMA_NO_LEAKDETECTION */
- DUMA_EXTERN_C void *_duma_allocate(size_t alignment, size_t userSize,
- int protectBelow, int fillByte,
- int protectAllocList,
- enum _DUMA_Allocator allocator,
- enum _DUMA_FailReturn fail);
- DUMA_EXTERN_C void _duma_deallocate(void *baseAdr, int protectAllocList,
- enum _DUMA_Allocator allocator);
- DUMA_EXTERN_C void *_duma_malloc(size_t size);
- DUMA_EXTERN_C void *_duma_calloc(size_t elemCount, size_t elemSize);
- DUMA_EXTERN_C void _duma_free(void *baseAdr);
- DUMA_EXTERN_C void *_duma_memalign(size_t alignment, size_t userSize);
- DUMA_EXTERN_C int _duma_posix_memalign(void **memptr, size_t alignment,
- size_t userSize);
- DUMA_EXTERN_C void *_duma_realloc(void *baseAdr, size_t newSize);
- DUMA_EXTERN_C void *_duma_valloc(size_t size);
- DUMA_EXTERN_C size_t _duma_malloc_usable_size(void *ptr);
- DUMA_EXTERN_C char *_duma_strdup(const char *str);
- DUMA_EXTERN_C void *_duma_memcpy(void *dest, const void *src, size_t size);
- DUMA_EXTERN_C void *_duma_memmove(void *dest, const void *src, size_t size);
- DUMA_EXTERN_C char *_duma_strcpy(char *dest, const char *src);
- DUMA_EXTERN_C char *_duma_strncpy(char *dest, const char *src, size_t size);
- DUMA_EXTERN_C char *_duma_strcat(char *dest, const char *src);
- DUMA_EXTERN_C char *_duma_strncat(char *dest, const char *src, size_t size);
- #endif /* DUMA_NO_LEAKDETECTION */
- #endif /* DUMA_FUNCTIONS_DECLARED */
- #ifndef DUMA_SKIP_SETUP
- #ifndef DUMA_NO_LEAKDETECTION
- #define malloc(SIZE) _duma_malloc(SIZE, __FILE__, __LINE__)
- #define calloc(ELEMCOUNT, ELEMSIZE) \
- _duma_calloc(ELEMCOUNT, ELEMSIZE, __FILE__, __LINE__)
- #define free(BASEADR) _duma_free(BASEADR, __FILE__, __LINE__)
- #define memalign(ALIGNMENT, SIZE) \
- _duma_memalign(ALIGNMENT, SIZE, __FILE__, __LINE__)
- #define posix_memalign(MEMPTR, ALIGNMENT, SIZE) \
- _duma_posix_memalign(MEMPTR, ALIGNMENT, SIZE, __FILE__, __LINE__)
- #define realloc(BASEADR, NEWSIZE) \
- _duma_realloc(BASEADR, NEWSIZE, __FILE__, __LINE__)
- #define valloc(SIZE) _duma_valloc(SIZE, __FILE__, __LINE__)
- #define malloc_usable_size(PTR) \
- _duma_malloc_usable_size(PTR, __FILE__, __LINE__)
- #define strdup(STR) _duma_strdup(STR, __FILE__, __LINE__)
- #define memcpy(DEST, SRC, SIZE) \
- _duma_memcpy(DEST, SRC, SIZE, __FILE__, __LINE__)
- #define memmove(DEST, SRC, SIZE) _duma_memmove(DEST, SRC, SIZE)
- #define strcpy(DEST, SRC) _duma_strcpy(DEST, SRC, __FILE__, __LINE__)
- #define strncpy(DEST, SRC, SIZE) \
- _duma_strncpy(DEST, SRC, SIZE, __FILE__, __LINE__)
- #define strcat(DEST, SRC) _duma_strcat(DEST, SRC, __FILE__, __LINE__)
- #define strncat(DEST, SRC, SIZE) \
- _duma_strncat(DEST, SRC, SIZE, __FILE__, __LINE__)
- #else /* DUMA_NO_LEAKDETECTION */
- #define DUMA_newFrame() \
- do { \
- } while (0)
- #define DUMA_delFrame() \
- do { \
- } while (0)
- #endif /* DUMA_NO_LEAKDETECTION */
- #endif // DUMA_SKIP_SETUP
- #ifndef DUMA_ASSERT
- #define DUMA_ASSERT(EXPR) \
- ((EXPR) || (_duma_assert(#EXPR, __FILE__, __LINE__), 0))
- #endif
- #ifndef DUMA_CHECK
- #define DUMA_CHECK(BASEADR) duma_check(BASEADR)
- #endif
- #ifndef DUMA_CHECKALL
- #define DUMA_CHECKALL() duma_checkAll()
- #endif
- /*
- * protection of functions return address
- */
- #ifdef __GNUC__
- #define DUMA_FN_PROT_START \
- const void *DUMA_RET_ADDR = __builtin_return_address(0); \
- {
- #define DUMA_FN_PROT_END \
- } \
- DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR);
- #define DUMA_FN_PROT_RET(EXPR) \
- do { \
- DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR); \
- return (EXPR); \
- } while (0)
- #define DUMA_FN_PROT_RET_VOID() \
- do { \
- DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR); \
- return; \
- } while (0)
- #else
- #define DUMA_FN_PROT_START \
- int aiDUMA_PROT[4] = {'E', 'F', 'P', 'R'}; \
- {
- #define DUMA_FN_PROT_END \
- } \
- DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
- 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]);
- #define DUMA_FN_PROT_RET(EXPR) \
- do { \
- DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
- 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]); \
- return (EXPR); \
- } while (0)
- #define DUMA_FN_PROT_RET_VOID() \
- do { \
- DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
- 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]); \
- return; \
- } while (0)
- #endif
- /* declaration of an already defined array to enable checking at every reference
- * when using CA_REF()
- */
- #define CA_DECLARE(NAME, SIZE) \
- const unsigned long NAME##_checkedsize = (SIZE); \
- unsigned long NAME##_checkedidx
- /* definition of a checked array adds definitions for its size and an extra
- * temporary. every array gets its own temporary to avoid problems with
- * threading a global temporary would have.
- */
- #define CA_DEFINE(TYPE, NAME, SIZE) \
- TYPE NAME[SIZE]; \
- CA_DECLARE(NAME, SIZE)
- /* every access to a checked array is preceded an assert() on the index;
- * the index parameter is stored to a temporary to avoid double execution of
- * index, when index contains f.e. a "++".
- */
- #define CA_REF(NAME, INDEX) \
- NAME[DUMA_ASSERT((NAME##_checkedidx = (INDEX)) < NAME##_checkedsize), \
- NAME##_checkedidx]
- #endif /* end ifdef DUMA_NO_DUMA */
|