duma.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. * DUMA - Red-Zone memory allocator.
  3. * Copyright (C) 2020-2022 Jeffrey H. Johnson <trnsz@pobox.com>
  4. * Copyright (C) 2006 Michael Eddington <meddington@gmail.com>
  5. * Copyright (C) 2002-2021 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
  6. * Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
  7. * License: GNU GPL (GNU General Public License, see COPYING-GPL)
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. *
  23. *
  24. * FILE CONTENTS:
  25. * header file for inclusion from YOUR application code
  26. */
  27. /* explicitly no "#ifndef _DUMA_H_" to allow mutliple inclusions
  28. * within single source file with inclusion of noduma.h in between
  29. */
  30. #include <stdlib.h>
  31. /*
  32. * #include <stdlib.h>
  33. *
  34. * You must include <stdlib.h> before including <duma.h> !
  35. *
  36. */
  37. /* for enabling inclusion of duma.h after inclusion of efencint.h */
  38. /* remove previous definitions */
  39. #define SKIP_DUMA_NO_CXX
  40. #include "noduma.h"
  41. #undef SKIP_DUMA_NO_CXX
  42. #include "duma_config.h"
  43. #ifdef __cplusplus
  44. #define DUMA_EXTERN_C extern "C"
  45. #else
  46. #define DUMA_EXTERN_C extern
  47. #endif
  48. #ifdef DUMA_NO_DUMA
  49. /* enable these macros even in release code, but do nothing */
  50. #define DUMA_newFrame() \
  51. do { \
  52. } while (0)
  53. #define DUMA_delFrame() \
  54. do { \
  55. } while (0)
  56. #define DUMA_SET_ALIGNMENT(V) \
  57. do { \
  58. } while (0)
  59. #define DUMA_SET_PROTECT_BELOW(V) \
  60. do { \
  61. } while (0)
  62. #define DUMA_SET_FILL(V) \
  63. do { \
  64. } while (0)
  65. #define DUMA_ASSERT(EXPR) \
  66. do { \
  67. } while (0)
  68. #define DUMA_CHECK(BASEADR) \
  69. do { \
  70. } while (0)
  71. #define DUMA_CHECKALL() \
  72. do { \
  73. } while (0)
  74. #define CA_DECLARE(NAME, SIZE) \
  75. do { \
  76. } while (0)
  77. #define CA_DEFINE(TYPE, NAME, SIZE) TYPE NAME[SIZE]
  78. #define CA_REF(NAME, INDEX) NAME[INDEX]
  79. #else /* ifndef DUMA_NO_DUMA */
  80. #ifndef DUMA_EXTERNS_DECLARED
  81. #define DUMA_EXTERNS_DECLARED
  82. /* global DUMA variables */
  83. DUMA_EXTERN_C int DUMA_OUTPUT_DEBUG;
  84. DUMA_EXTERN_C int DUMA_OUTPUT_STDOUT;
  85. DUMA_EXTERN_C int DUMA_OUTPUT_STDERR;
  86. DUMA_EXTERN_C char *DUMA_OUTPUT_FILE;
  87. DUMA_EXTERN_C int DUMA_OUTPUT_STACKTRACE;
  88. #endif /* DUMA_EXTERNS_DECLARED */
  89. /* set Maximum Delete Depth (depth of recursive destructor calls) */
  90. #ifndef DUMA_MAX_DEL_DEPTH
  91. #define DUMA_MAX_DEL_DEPTH 256
  92. #endif
  93. #ifndef DUMA_TLSVARTYPE_DEFINED
  94. #define DUMA_TLSVARTYPE_DEFINED
  95. /* GitHub #82 - following variables should exist per thread ("thread-local") */
  96. typedef struct {
  97. /*
  98. * ALIGNMENT is a global variable used to control the default alignment
  99. * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
  100. * so that its name matches the name of the environment variable that is used
  101. * to set it. This gives the programmer one less name to remember.
  102. */
  103. int ALIGNMENT;
  104. /*
  105. * PROTECT_BELOW is used to modify the behavior of the allocator. When
  106. * its value is non-zero, the allocator will place an inaccessable page
  107. * immediately _before_ the malloc buffer in the address space, instead
  108. * of _after_ it. Use this to detect malloc buffer under-runs, rather than
  109. * over-runs. It won't detect both at the same time, so you should test your
  110. * software twice, once with this value clear, and once with it set.
  111. */
  112. int PROTECT_BELOW;
  113. /*
  114. * FILL is set to 0-255 if DUMA should fill all new allocated
  115. * memory with the specified value. Set to -1 when DUMA should not
  116. * initialise allocated memory.
  117. * default is set to initialise with 255, cause many programs rely on
  118. * initialisation to 0!
  119. */
  120. int FILL;
  121. #if !defined(DUMA_NO_CPP_SUPPORT) && !defined(DUMA_NO_LEAKDETECTION)
  122. int Magic;
  123. int DelPtr;
  124. const char *DelFile[DUMA_MAX_DEL_DEPTH];
  125. int DelLine[DUMA_MAX_DEL_DEPTH];
  126. #endif
  127. } DUMA_TLSVARS_T;
  128. #endif
  129. #ifndef DUMA_GLOBALS_DEFINED
  130. #define DUMA_GLOBALS_DEFINED
  131. typedef struct {
  132. /* Protection Space A */
  133. char acSpaceA[2 * DUMA_PAGE_SIZE];
  134. /* Variable: _duma_allocList
  135. *
  136. * _DUMA_allocList points to the array of slot structures used to manage the
  137. * malloc arena.
  138. */
  139. struct _DUMA_Slot *allocList;
  140. /* Variable: _duma_null_addr
  141. *
  142. * _duma_null_addr is the address malloc() or C++ operator new returns, when
  143. * size is 0 two pages get reserved and protected
  144. */
  145. void *null_addr;
  146. /* Variable */
  147. DUMA_TLSVARS_T TLS;
  148. /* Protection Space B */
  149. char acSpaceB[2 * DUMA_PAGE_SIZE];
  150. } DUMA_GLOBALVARS_T;
  151. DUMA_EXTERN_C DUMA_GLOBALVARS_T _duma_g;
  152. #endif /* DUMA_GLOBALS_DEFINED */
  153. #define GET_DUMA_TLSVARS() (&_duma_g.TLS)
  154. #ifndef DUMA_SET_ALIGNMENT
  155. #define DUMA_SET_ALIGNMENT(V) GET_DUMA_TLSVARS()->ALIGNMENT = (V)
  156. #endif
  157. #ifndef DUMA_SET_PROTECT_BELOW
  158. #define DUMA_SET_PROTECT_BELOW(V) GET_DUMA_TLSVARS()->PROTECT_BELOW = (V)
  159. #endif
  160. #ifndef DUMA_SET_FILL
  161. #define DUMA_SET_FILL(V) GET_DUMA_TLSVARS()->FILL = (V)
  162. #endif
  163. #ifndef DUMA_ENUMS_DECLARED
  164. #define DUMA_ENUMS_DECLARED
  165. /* allocator defines the type of calling allocator/deallocator function */
  166. enum _DUMA_Allocator {
  167. EFA_INT_ALLOC,
  168. EFA_INT_DEALLOC,
  169. EFA_MALLOC,
  170. EFA_CALLOC,
  171. EFA_FREE,
  172. EFA_MEMALIGN,
  173. EFA_POSIX_MEMALIGN,
  174. EFA_REALLOC,
  175. EFA_VALLOC,
  176. EFA_STRDUP,
  177. EFA_NEW_ELEM,
  178. EFA_DEL_ELEM,
  179. EFA_NEW_ARRAY,
  180. EFA_DEL_ARRAY
  181. /* use following enums when calling _duma_allocate()/_duma_deallocate()
  182. * from user defined member operators
  183. */
  184. ,
  185. EFA_MEMBER_NEW_ELEM,
  186. EFA_MEMBER_DEL_ELEM,
  187. EFA_MEMBER_NEW_ARRAY,
  188. EFA_MEMBER_DEL_ARRAY
  189. };
  190. enum _DUMA_FailReturn { DUMA_FAIL_NULL, DUMA_FAIL_ENV };
  191. #endif /* DUMA_ENUMS_DECLARED */
  192. #ifndef DUMA_FUNCTIONS_DECLARED
  193. #define DUMA_FUNCTIONS_DECLARED
  194. DUMA_EXTERN_C void _duma_init(void);
  195. DUMA_EXTERN_C void _duma_assert(const char *exprstr, const char *filename,
  196. int lineno);
  197. DUMA_EXTERN_C void duma_check(void *address);
  198. DUMA_EXTERN_C void duma_checkAll();
  199. DUMA_EXTERN_C void *duma_alloc_return(void *address);
  200. #ifdef DUMA_EXPLICIT_INIT
  201. DUMA_EXTERN_C void duma_init(void);
  202. #endif
  203. #ifndef DUMA_NO_LEAKDETECTION
  204. DUMA_EXTERN_C void *_duma_allocate(size_t alignment, size_t userSize,
  205. int protectBelow, int fillByte,
  206. int protectAllocList,
  207. enum _DUMA_Allocator allocator,
  208. enum _DUMA_FailReturn fail,
  209. const char *filename, int lineno);
  210. DUMA_EXTERN_C void _duma_deallocate(void *baseAdr, int protectAllocList,
  211. enum _DUMA_Allocator allocator,
  212. const char *filename, int lineno);
  213. DUMA_EXTERN_C void *_duma_malloc(size_t size, const char *filename, int lineno);
  214. DUMA_EXTERN_C void *_duma_calloc(size_t elemCount, size_t elemSize,
  215. const char *filename, int lineno);
  216. DUMA_EXTERN_C void _duma_free(void *baseAdr, const char *filename, int lineno);
  217. DUMA_EXTERN_C void *_duma_memalign(size_t alignment, size_t userSize,
  218. const char *filename, int lineno);
  219. DUMA_EXTERN_C int _duma_posix_memalign(void **memptr, size_t alignment,
  220. size_t userSize, const char *filename,
  221. int lineno);
  222. DUMA_EXTERN_C void *_duma_realloc(void *baseAdr, size_t newSize,
  223. const char *filename, int lineno);
  224. DUMA_EXTERN_C void *_duma_valloc(size_t size, const char *filename, int lineno);
  225. DUMA_EXTERN_C size_t _duma_malloc_usable_size(void *ptr, const char *filename,
  226. int lineno);
  227. DUMA_EXTERN_C char *_duma_strdup(const char *str, const char *filename,
  228. int lineno);
  229. DUMA_EXTERN_C void *_duma_memcpy(void *dest, const void *src, size_t size,
  230. const char *filename, int lineno);
  231. DUMA_EXTERN_C void *_duma_memmove(void *dest, const void *src, size_t size);
  232. DUMA_EXTERN_C char *_duma_strcpy(char *dest, const char *src,
  233. const char *filename, int lineno);
  234. DUMA_EXTERN_C char *_duma_strncpy(char *dest, const char *src, size_t size,
  235. const char *filename, int lineno);
  236. DUMA_EXTERN_C char *_duma_strcat(char *dest, const char *src,
  237. const char *filename, int lineno);
  238. DUMA_EXTERN_C char *_duma_strncat(char *dest, const char *src, size_t size,
  239. const char *filename, int lineno);
  240. DUMA_EXTERN_C void DUMA_newFrame(void);
  241. DUMA_EXTERN_C void DUMA_delFrame(void);
  242. #else /* DUMA_NO_LEAKDETECTION */
  243. DUMA_EXTERN_C void *_duma_allocate(size_t alignment, size_t userSize,
  244. int protectBelow, int fillByte,
  245. int protectAllocList,
  246. enum _DUMA_Allocator allocator,
  247. enum _DUMA_FailReturn fail);
  248. DUMA_EXTERN_C void _duma_deallocate(void *baseAdr, int protectAllocList,
  249. enum _DUMA_Allocator allocator);
  250. DUMA_EXTERN_C void *_duma_malloc(size_t size);
  251. DUMA_EXTERN_C void *_duma_calloc(size_t elemCount, size_t elemSize);
  252. DUMA_EXTERN_C void _duma_free(void *baseAdr);
  253. DUMA_EXTERN_C void *_duma_memalign(size_t alignment, size_t userSize);
  254. DUMA_EXTERN_C int _duma_posix_memalign(void **memptr, size_t alignment,
  255. size_t userSize);
  256. DUMA_EXTERN_C void *_duma_realloc(void *baseAdr, size_t newSize);
  257. DUMA_EXTERN_C void *_duma_valloc(size_t size);
  258. DUMA_EXTERN_C size_t _duma_malloc_usable_size(void *ptr);
  259. DUMA_EXTERN_C char *_duma_strdup(const char *str);
  260. DUMA_EXTERN_C void *_duma_memcpy(void *dest, const void *src, size_t size);
  261. DUMA_EXTERN_C void *_duma_memmove(void *dest, const void *src, size_t size);
  262. DUMA_EXTERN_C char *_duma_strcpy(char *dest, const char *src);
  263. DUMA_EXTERN_C char *_duma_strncpy(char *dest, const char *src, size_t size);
  264. DUMA_EXTERN_C char *_duma_strcat(char *dest, const char *src);
  265. DUMA_EXTERN_C char *_duma_strncat(char *dest, const char *src, size_t size);
  266. #endif /* DUMA_NO_LEAKDETECTION */
  267. #endif /* DUMA_FUNCTIONS_DECLARED */
  268. #ifndef DUMA_SKIP_SETUP
  269. #ifndef DUMA_NO_LEAKDETECTION
  270. #define malloc(SIZE) _duma_malloc(SIZE, __FILE__, __LINE__)
  271. #define calloc(ELEMCOUNT, ELEMSIZE) \
  272. _duma_calloc(ELEMCOUNT, ELEMSIZE, __FILE__, __LINE__)
  273. #define free(BASEADR) _duma_free(BASEADR, __FILE__, __LINE__)
  274. #define memalign(ALIGNMENT, SIZE) \
  275. _duma_memalign(ALIGNMENT, SIZE, __FILE__, __LINE__)
  276. #define posix_memalign(MEMPTR, ALIGNMENT, SIZE) \
  277. _duma_posix_memalign(MEMPTR, ALIGNMENT, SIZE, __FILE__, __LINE__)
  278. #define realloc(BASEADR, NEWSIZE) \
  279. _duma_realloc(BASEADR, NEWSIZE, __FILE__, __LINE__)
  280. #define valloc(SIZE) _duma_valloc(SIZE, __FILE__, __LINE__)
  281. #define malloc_usable_size(PTR) \
  282. _duma_malloc_usable_size(PTR, __FILE__, __LINE__)
  283. #define strdup(STR) _duma_strdup(STR, __FILE__, __LINE__)
  284. #define memcpy(DEST, SRC, SIZE) \
  285. _duma_memcpy(DEST, SRC, SIZE, __FILE__, __LINE__)
  286. #define memmove(DEST, SRC, SIZE) _duma_memmove(DEST, SRC, SIZE)
  287. #define strcpy(DEST, SRC) _duma_strcpy(DEST, SRC, __FILE__, __LINE__)
  288. #define strncpy(DEST, SRC, SIZE) \
  289. _duma_strncpy(DEST, SRC, SIZE, __FILE__, __LINE__)
  290. #define strcat(DEST, SRC) _duma_strcat(DEST, SRC, __FILE__, __LINE__)
  291. #define strncat(DEST, SRC, SIZE) \
  292. _duma_strncat(DEST, SRC, SIZE, __FILE__, __LINE__)
  293. #else /* DUMA_NO_LEAKDETECTION */
  294. #define DUMA_newFrame() \
  295. do { \
  296. } while (0)
  297. #define DUMA_delFrame() \
  298. do { \
  299. } while (0)
  300. #endif /* DUMA_NO_LEAKDETECTION */
  301. #endif // DUMA_SKIP_SETUP
  302. #ifndef DUMA_ASSERT
  303. #define DUMA_ASSERT(EXPR) \
  304. ((EXPR) || (_duma_assert(#EXPR, __FILE__, __LINE__), 0))
  305. #endif
  306. #ifndef DUMA_CHECK
  307. #define DUMA_CHECK(BASEADR) duma_check(BASEADR)
  308. #endif
  309. #ifndef DUMA_CHECKALL
  310. #define DUMA_CHECKALL() duma_checkAll()
  311. #endif
  312. /*
  313. * protection of functions return address
  314. */
  315. #ifdef __GNUC__
  316. #define DUMA_FN_PROT_START \
  317. const void *DUMA_RET_ADDR = __builtin_return_address(0); \
  318. {
  319. #define DUMA_FN_PROT_END \
  320. } \
  321. DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR);
  322. #define DUMA_FN_PROT_RET(EXPR) \
  323. do { \
  324. DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR); \
  325. return (EXPR); \
  326. } while (0)
  327. #define DUMA_FN_PROT_RET_VOID() \
  328. do { \
  329. DUMA_ASSERT(__builtin_return_address(0) == DUMA_RET_ADDR); \
  330. return; \
  331. } while (0)
  332. #else
  333. #define DUMA_FN_PROT_START \
  334. int aiDUMA_PROT[4] = {'E', 'F', 'P', 'R'}; \
  335. {
  336. #define DUMA_FN_PROT_END \
  337. } \
  338. DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
  339. 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]);
  340. #define DUMA_FN_PROT_RET(EXPR) \
  341. do { \
  342. DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
  343. 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]); \
  344. return (EXPR); \
  345. } while (0)
  346. #define DUMA_FN_PROT_RET_VOID() \
  347. do { \
  348. DUMA_ASSERT('E' == aiDUMA_PROT[0] && 'F' == aiDUMA_PROT[1] && \
  349. 'P' == aiDUMA_PROT[2] && 'R' == aiDUMA_PROT[3]); \
  350. return; \
  351. } while (0)
  352. #endif
  353. /* declaration of an already defined array to enable checking at every reference
  354. * when using CA_REF()
  355. */
  356. #define CA_DECLARE(NAME, SIZE) \
  357. const unsigned long NAME##_checkedsize = (SIZE); \
  358. unsigned long NAME##_checkedidx
  359. /* definition of a checked array adds definitions for its size and an extra
  360. * temporary. every array gets its own temporary to avoid problems with
  361. * threading a global temporary would have.
  362. */
  363. #define CA_DEFINE(TYPE, NAME, SIZE) \
  364. TYPE NAME[SIZE]; \
  365. CA_DECLARE(NAME, SIZE)
  366. /* every access to a checked array is preceded an assert() on the index;
  367. * the index parameter is stored to a temporary to avoid double execution of
  368. * index, when index contains f.e. a "++".
  369. */
  370. #define CA_REF(NAME, INDEX) \
  371. NAME[DUMA_ASSERT((NAME##_checkedidx = (INDEX)) < NAME##_checkedsize), \
  372. NAME##_checkedidx]
  373. #endif /* end ifdef DUMA_NO_DUMA */