00001 #ifndef MALLOC_CHECK_H
00002 #define MALLOC_CHECK_H 1
00003
00004 #ifndef MALLOC_CHECK__ATTR_USED
00005 #if defined(__GNUC__) && (__GNUC__ > 3)
00006 # define MALLOC_CHECK__ATTR_USED() __attribute__((__used__))
00007 #else
00008 # define MALLOC_CHECK__ATTR_USED()
00009 #endif
00010 #endif
00011
00012 #ifndef MALLOC_CHECK__ATTR_H
00013 #if defined(__GNUC__) && (__GNUC__ > 3)
00014 # define MALLOC_CHECK__ATTR_H() __attribute__((__visibility__("hidden")))
00015 #else
00016 # define MALLOC_CHECK__ATTR_H()
00017 #endif
00018 #endif
00019
00020 #ifndef MALLOC_CHECK__ATTR_MALLOC
00021 #if defined(__GNUC__) && (__GNUC__ > 3)
00022 # define MALLOC_CHECK__ATTR_MALLOC() __attribute__ ((__malloc__))
00023 #else
00024 # define MALLOC_CHECK__ATTR_MALLOC()
00025 #endif
00026 #endif
00027
00028 #ifndef MALLOC_CHECK_API_M_SCRUB
00029 #define MALLOC_CHECK_API_M_SCRUB 0
00030 #endif
00031
00032 #ifndef MALLOC_CHECK_API_F_SCRUB
00033 #define MALLOC_CHECK_API_F_SCRUB 0
00034 #endif
00035
00036 #ifndef MALLOC_CHECK_API_R_SCRUB
00037 #define MALLOC_CHECK_API_R_SCRUB 0
00038 #endif
00039
00040 #ifndef MALLOC_CHECK_STORE
00041 #define MALLOC_CHECK_STORE malloc_check__app_store
00042 #endif
00043
00044
00045 #define MALLOC_CHECK_REINIT() \
00046 MALLOC_CHECK_STORE.mem_sz = 0; \
00047 MALLOC_CHECK_STORE.mem_num = 0; \
00048 MALLOC_CHECK_STORE.mem_vals = NULL
00049 #define MALLOC_CHECK_INIT() \
00050 MALLOC_CHECK_STORE.mem_fail_num = 0; \
00051 MALLOC_CHECK_REINIT()
00052
00053 #ifndef USE_MALLOC_CHECK
00054 #ifndef NDEBUG
00055 # define USE_MALLOC_CHECK 1
00056 # else
00057 # define USE_MALLOC_CHECK 0
00058 # endif
00059 #endif
00060
00061 #ifndef MALLOC_CHECK_FUNC_NAME
00062 #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
00063 (defined(__GNUC__) && (__GNUC__ > 3) && !defined(__STRICT_ANSI__))
00064 # define MALLOC_CHECK_FUNC_NAME __func__
00065 #else
00066 # define MALLOC_CHECK_FUNC_NAME ""
00067 #endif
00068 #endif
00069
00070 #define MALLOC_CHECK_MEM(x) \
00071 malloc_check_mem(x, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00072 #define MALLOC_CHECK_MEM_SZ(x, y) \
00073 malloc_check_mem_sz(x, y, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00074 #define MALLOC_CHECK_MEM_MINSZ(x, y) \
00075 malloc_check_mem_minsz(x, y, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00076 #define MALLOC_CHECK_EMPTY() \
00077 malloc_check_empty(__FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00078
00079
00080 #define MC_MALLOC(x) \
00081 malloc_check_malloc(x, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00082 #define MC_CALLOC(x, y) \
00083 malloc_check_calloc(x, y, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00084 #define MC_REALLOC(x, y) \
00085 malloc_check_realloc(x, y, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00086 #define MC_FREE(x) \
00087 malloc_check_free(x, __FILE__, __LINE__, MALLOC_CHECK_FUNC_NAME)
00088
00089 #if !(USE_MALLOC_CHECK)
00090 #define MALLOC_CHECK_DECL() \
00091 static Malloc_check_store MALLOC_CHECK_STORE = {0, 0, 0, NULL}
00092
00093 # define MALLOC_CHECK_FAIL_IN(x)
00094 # define MALLOC_CHECK_SCRUB_PTR(x, y)
00095
00096 # define malloc_check_mem(x, Fi, L, Fu) (1)
00097 # define malloc_check_mem_sz(x, y, Fi, L, Fu) (1)
00098 # define malloc_check_mem_minsz(x, y, Fi, L, Fu) (1)
00099 # define malloc_check_empty(Fi, L, Fu)
00100
00101 # define malloc_check_malloc(x, Fi, L, Fu) malloc(x)
00102 # define malloc_check_calloc(x, y, Fi, L, Fu) calloc(x, y)
00103 # define malloc_check_realloc(x, y, Fi, L, Fu) realloc(x, y)
00104 # define malloc_check_free(x, Fi, L, Fu) free(x)
00105
00106 #else
00107
00108 #include <stdio.h>
00109 #include <stdlib.h>
00110 #include <string.h>
00111
00112 typedef struct Malloc_check_vals
00113 {
00114 void *ptr;
00115 size_t sz;
00116 const char *file;
00117 unsigned int line;
00118 const char *func;
00119 } Malloc_check_vals;
00120
00121 typedef struct Malloc_check_store
00122 {
00123 unsigned long mem_sz;
00124 unsigned long mem_num;
00125 unsigned long mem_fail_num;
00126 Malloc_check_vals *mem_vals;
00127 } Malloc_check_store;
00128
00129 #ifndef MALLOC_CHECK_SCOPE_EXTERN
00130 #define MALLOC_CHECK_SCOPE_EXTERN 1
00131 #endif
00132
00133 #if MALLOC_CHECK_SCOPE_EXTERN
00134 extern Malloc_check_store MALLOC_CHECK__ATTR_H() MALLOC_CHECK_STORE;
00135 #else
00136 static Malloc_check_store MALLOC_CHECK_STORE;
00137 #endif
00138
00139
00140 #define malloc_check_assert(x) do { \
00141 if (x) {} else { \
00142 fprintf(stderr, " -=> mc_assert (%s) failed, caller=%s:%s:%d.\n", \
00143 #x , func, file, line); \
00144 abort(); } \
00145 } while (0)
00146 #define MALLOC_CHECK_ASSERT(x) do { \
00147 if (x) {} else { \
00148 fprintf(stderr, " -=> MC_ASSERT (%s) failed, caller=%s:%s:%d.\n", \
00149 #x , func, file, line); \
00150 abort(); } \
00151 } while (0)
00152
00153 #if MALLOC_CHECK_SCOPE_EXTERN
00154 #define MALLOC_CHECK_DECL() \
00155 Malloc_check_store MALLOC_CHECK_STORE = {0, 0, 0, NULL}
00156 #else
00157 #define MALLOC_CHECK_DECL() \
00158 static Malloc_check_store MALLOC_CHECK_STORE = {0, 0, 0, NULL}
00159 #endif
00160
00161 # define MALLOC_CHECK_DEC() \
00162 (MALLOC_CHECK_STORE.mem_fail_num && !--MALLOC_CHECK_STORE.mem_fail_num)
00163 # define MALLOC_CHECK_FAIL_IN(x) MALLOC_CHECK_STORE.mem_fail_num = (x)
00164 # define MALLOC_CHECK_SCRUB_PTR(x, y) memset(x, 0xa5, y)
00165
00166 #ifndef MALLOC_CHECK_PRINT
00167 #define MALLOC_CHECK_PRINT 1
00168 #endif
00169
00170 #ifndef MALLOC_CHECK_TRACE
00171 #define MALLOC_CHECK_TRACE 0
00172 #endif
00173
00174 #ifndef MALLOC_CHECK_SWAP_TYPE
00175 #define MALLOC_CHECK_SWAP_TYPE(x, y, type) do { \
00176 type internal_local_tmp = (x); \
00177 (x) = (y); \
00178 (y) = internal_local_tmp; \
00179 } while (0)
00180 #endif
00181
00182 static void malloc_check_alloc(const char *, unsigned int, const char *)
00183 MALLOC_CHECK__ATTR_USED();
00184 static unsigned int malloc_check_mem(const void *, const char *, unsigned int, const char *)
00185 MALLOC_CHECK__ATTR_USED();
00186 static unsigned int malloc_check_mem_sz(const void *, size_t, const char *, unsigned int, const char *)
00187 MALLOC_CHECK__ATTR_USED();
00188 static unsigned int malloc_check_mem_minsz(const void *, size_t, const char *, unsigned int, const char *)
00189 MALLOC_CHECK__ATTR_USED();
00190 static void *malloc_check_malloc(size_t, const char *, unsigned int, const char *)
00191 MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
00192 static void *malloc_check_calloc(size_t, size_t, const char *, unsigned int, const char *)
00193 MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
00194 static void malloc_check_free(void *, const char *, unsigned int, const char *)
00195 MALLOC_CHECK__ATTR_USED();
00196 static void *malloc_check_realloc(void *, size_t,
00197 const char *, unsigned int, const char *)
00198 MALLOC_CHECK__ATTR_MALLOC() MALLOC_CHECK__ATTR_USED();
00199 static void malloc_check_empty(const char *, unsigned int, const char *)
00200 MALLOC_CHECK__ATTR_USED();
00201
00202 static
00203 void malloc_check_alloc(const char *file, unsigned int line, const char *func)
00204 {
00205 size_t sz = MALLOC_CHECK_STORE.mem_sz;
00206
00207 ++MALLOC_CHECK_STORE.mem_num;
00208
00209 if (!MALLOC_CHECK_STORE.mem_sz)
00210 {
00211 sz = 8;
00212 MALLOC_CHECK_STORE.mem_vals = malloc(sizeof(Malloc_check_vals) * sz);
00213 }
00214 else if (MALLOC_CHECK_STORE.mem_num > MALLOC_CHECK_STORE.mem_sz)
00215 {
00216 sz *= 2;
00217 MALLOC_CHECK_STORE.mem_vals = realloc(MALLOC_CHECK_STORE.mem_vals,
00218 sizeof(Malloc_check_vals) * sz);
00219 }
00220 malloc_check_assert(MALLOC_CHECK_STORE.mem_num <= sz);
00221 malloc_check_assert(MALLOC_CHECK_STORE.mem_vals);
00222
00223 MALLOC_CHECK_STORE.mem_sz = sz;
00224 }
00225
00226 static unsigned int malloc_check_mem(const void *ptr, const
00227 char *file, unsigned int line,
00228 const char *func)
00229 {
00230 unsigned int scan = 0;
00231
00232 malloc_check_assert(MALLOC_CHECK_STORE.mem_num);
00233
00234 while (MALLOC_CHECK_STORE.mem_vals[scan].ptr &&
00235 (MALLOC_CHECK_STORE.mem_vals[scan].ptr != ptr))
00236 ++scan;
00237
00238 malloc_check_assert(MALLOC_CHECK_STORE.mem_vals[scan].ptr);
00239
00240 return (scan);
00241 }
00242
00243 static unsigned int malloc_check_mem_sz(const void *ptr, size_t sz,
00244 const char *file, unsigned int line,
00245 const char *func)
00246 {
00247 unsigned int scan = malloc_check_mem(ptr, file, line, func);
00248
00249 malloc_check_assert(MALLOC_CHECK_STORE.mem_vals[scan].sz == sz);
00250
00251 return (scan);
00252 }
00253
00254 static unsigned int malloc_check_mem_minsz(const void *ptr, size_t sz,
00255 const char *file, unsigned int line,
00256 const char *func)
00257 {
00258 unsigned int scan = malloc_check_mem(ptr, file, line, func);
00259
00260 malloc_check_assert(MALLOC_CHECK_STORE.mem_vals[scan].sz >= sz);
00261
00262 return (scan);
00263 }
00264
00265 static void *malloc_check_malloc(size_t sz, const char *file, unsigned int line,
00266 const char *func)
00267 {
00268 void *ret = NULL;
00269
00270 if (MALLOC_CHECK_DEC())
00271 return (NULL);
00272
00273 malloc_check_alloc(file, line, func);
00274
00275 MALLOC_CHECK_ASSERT(sz);
00276
00277 ret = malloc(sz);
00278 MALLOC_CHECK_ASSERT(ret);
00279 if (!ret)
00280 return (NULL);
00281
00282 if (MALLOC_CHECK_TRACE)
00283 fprintf(stderr, "mc_make(%zu, %s, %u, %s) = %p\n", sz, file,line,func, ret);
00284
00285 if (MALLOC_CHECK_API_M_SCRUB)
00286 MALLOC_CHECK_SCRUB_PTR(ret, sz);
00287
00288 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].ptr = ret;
00289 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].sz = sz;
00290 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].file = file;
00291 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].line = line;
00292 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num - 1].func = func;
00293
00294 return (ret);
00295 }
00296
00297 static void *malloc_check_calloc(size_t num, size_t sz,
00298 const char *file, unsigned int line,
00299 const char *func)
00300 {
00301 size_t real_sz = num * sz;
00302 void *ret = NULL;
00303
00304 if ((num != 0) && ((real_sz / sz) != num))
00305 return (NULL);
00306 if (!(ret = malloc_check_malloc(real_sz, file, line, func)))
00307 return (NULL);
00308
00309 memset(ret, 0, real_sz);
00310 return (ret);
00311 }
00312
00313 static void malloc_check_free(void *ptr, const char *file, unsigned int line,
00314 const char *func)
00315 {
00316 if (MALLOC_CHECK_TRACE)
00317 fprintf(stderr, "mc_free(%s, %u, %s, %p)\n", file, line, func, ptr);
00318
00319 if (ptr)
00320 {
00321 unsigned int scan = malloc_check_mem(ptr, file, line, func);
00322 size_t sz = 0;
00323
00324 malloc_check_assert(MALLOC_CHECK_STORE.mem_num > 0);
00325 --MALLOC_CHECK_STORE.mem_num;
00326
00327 sz = MALLOC_CHECK_STORE.mem_vals[scan].sz;
00328 if (scan != MALLOC_CHECK_STORE.mem_num)
00329 {
00330 unsigned int num = MALLOC_CHECK_STORE.mem_num;
00331 Malloc_check_vals *val1 = &MALLOC_CHECK_STORE.mem_vals[scan];
00332 Malloc_check_vals *val2 = &MALLOC_CHECK_STORE.mem_vals[num];
00333
00334 MALLOC_CHECK_SWAP_TYPE(val1->ptr, val2->ptr, void *);
00335 MALLOC_CHECK_SWAP_TYPE(val1->sz, val2->sz, size_t);
00336 MALLOC_CHECK_SWAP_TYPE(val1->file, val2->file, const char *);
00337 MALLOC_CHECK_SWAP_TYPE(val1->line, val2->line, unsigned int);
00338 MALLOC_CHECK_SWAP_TYPE(val1->func, val2->func, const char *);
00339 }
00340 MALLOC_CHECK_STORE.mem_vals[MALLOC_CHECK_STORE.mem_num].ptr = NULL;
00341
00342 if (MALLOC_CHECK_API_F_SCRUB)
00343 MALLOC_CHECK_SCRUB_PTR(ptr, sz);
00344
00345 free(ptr);
00346 }
00347 }
00348
00349 static void *malloc_check_realloc(void *ptr, size_t sz,
00350 const char *file, unsigned int line,
00351 const char *func)
00352 {
00353 void *ret = NULL;
00354 unsigned int scan = malloc_check_mem(ptr, file, line, func);
00355
00356 MALLOC_CHECK_ASSERT(ptr && sz);
00357
00358 if (MALLOC_CHECK_API_R_SCRUB)
00359 {
00360 if (!(ret = malloc_check_malloc(sz, file, line, func)))
00361 return (NULL);
00362
00363 if (sz >= MALLOC_CHECK_STORE.mem_vals[scan].sz)
00364 sz = MALLOC_CHECK_STORE.mem_vals[scan].sz;
00365 if (sz)
00366 memcpy(ret, ptr, sz);
00367
00368 malloc_check_free(ptr, file, line, func);
00369
00370 return (ret);
00371 }
00372
00373 if (MALLOC_CHECK_DEC())
00374 return (NULL);
00375
00376 ret = realloc(ptr, sz);
00377 MALLOC_CHECK_ASSERT(ret);
00378 if (!ret)
00379 return (NULL);
00380
00381 if (MALLOC_CHECK_TRACE)
00382 fprintf(stderr, "mc_realloc(%p, %zu, %s, %u) = %p\n",
00383 ptr, sz, file, line, ret);
00384
00385 MALLOC_CHECK_STORE.mem_vals[scan].ptr = ret;
00386 MALLOC_CHECK_STORE.mem_vals[scan].sz = sz;
00387 MALLOC_CHECK_STORE.mem_vals[scan].file = file;
00388 MALLOC_CHECK_STORE.mem_vals[scan].line = line;
00389 MALLOC_CHECK_STORE.mem_vals[scan].func = func;
00390
00391 return (ret);
00392 }
00393
00394 static
00395 void malloc_check_empty(const char *file, unsigned int line, const char *func)
00396 {
00397 if (MALLOC_CHECK_PRINT && MALLOC_CHECK_STORE.mem_num)
00398 {
00399 unsigned int scan = 0;
00400
00401 while (MALLOC_CHECK_STORE.mem_vals[scan].ptr)
00402 {
00403
00404 fprintf(stderr," MEM CHECK NOT EMPTY: ptr %p, sz %lu, from %s:%u:%s\n",
00405 MALLOC_CHECK_STORE.mem_vals[scan].ptr,
00406 (unsigned long)MALLOC_CHECK_STORE.mem_vals[scan].sz,
00407 MALLOC_CHECK_STORE.mem_vals[scan].func,
00408 MALLOC_CHECK_STORE.mem_vals[scan].line,
00409 MALLOC_CHECK_STORE.mem_vals[scan].file);
00410 ++scan;
00411 }
00412 }
00413 malloc_check_assert(!MALLOC_CHECK_STORE.mem_num);
00414 }
00415 #endif
00416
00417 #endif