00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00028 #include "dnxHeap.h"
00029
00030 #include <stddef.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <assert.h>
00035 #include <pthread.h>
00036
00037 #define PICKETSZ 8
00038
00039 #define PICKET1 0xAA
00040 #define PICKET2 0xBB
00041 #define PICKET3 0xCC
00042 #define ALIGNED 0xDD
00043 #define ALLOCED 0xEE
00044 #define FREED 0xFF
00045
00046
00050 #define ALIGNSZ(sz) (((sz) + 15) & (-1L << 4))
00051
00053 typedef struct overhead_
00054 {
00055 char picket1[PICKETSZ];
00056 struct overhead_ * next;
00057 size_t reqsz;
00058 size_t actualsz;
00059 char * file;
00060 int line;
00061 char picket2[PICKETSZ];
00062 } overhead;
00063
00064 static overhead * head = 0;
00065 static int blkcnt = 0;
00066 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
00068
00069
00070
00071
00072
00077 static void link_block(overhead * ohp)
00078 {
00079 pthread_mutex_lock(&list_lock);
00080 ohp->next = head;
00081 head = ohp;
00082 blkcnt++;
00083 pthread_mutex_unlock(&list_lock);
00084 }
00085
00086
00087
00094 static int unlink_block(overhead * ohp)
00095 {
00096 int found = 0;
00097 overhead ** cpp;
00098 pthread_mutex_lock(&list_lock);
00099 for (cpp = &head; *cpp; cpp = &(*cpp)->next)
00100 if (*cpp == ohp)
00101 {
00102 *cpp = ohp->next;
00103 blkcnt--;
00104 found = 1;
00105 break;
00106 }
00107 pthread_mutex_unlock(&list_lock);
00108 return found;
00109 }
00110
00111
00112
00123 static size_t hex_dump(char * buf, void * p, size_t sz)
00124 {
00125 unsigned char * ucp = (unsigned char *)p;
00126 char * cp = buf;
00127
00128 while (sz--)
00129 cp += sprintf(cp, " %02x", *ucp++);
00130
00131 *cp = 0;
00132
00133 return cp - buf;
00134 }
00135
00136
00137
00143 static void dump_block(overhead * ohp, char * msg)
00144 {
00145 char buf[512];
00146 char * p = buf;
00147
00148
00149 p += sprintf(p, "dnxHeap:");
00150 if (msg) p += sprintf(p, " %s -", msg);
00151 p+= sprintf(p, " %d bytes allocated at %s(%d): ",
00152 ohp->reqsz, ohp->file, ohp->line);
00153 p += hex_dump(p, ohp->picket1, sizeof ohp->picket1);
00154 p += sprintf(p, " |");
00155 p += hex_dump(p, ohp->picket2, sizeof ohp->picket2);
00156 p += sprintf(p, " |");
00157 if (ohp->reqsz <= 16)
00158 p += hex_dump(p, &ohp[1], ohp->reqsz);
00159 else
00160 {
00161 p += hex_dump(p, &ohp[1], 8);
00162 p += sprintf (p, " ...");
00163 p += hex_dump(p, (char *)&ohp[1] + ohp->reqsz - 8, 8);
00164 }
00165 p += sprintf(p, " |");
00166 p += hex_dump(p, (char *)&ohp[1] + ohp->reqsz, PICKETSZ);
00167
00168
00169 dnxDebug(1, "%s", buf);
00170 }
00171
00172
00173
00183 static int memscan(void * p, unsigned char ch, size_t sz)
00184 {
00185 unsigned char * bp = (unsigned char *)p;
00186 unsigned char * ep = bp + sz;
00187 while (bp < ep) if (*bp++ != ch) return -1;
00188 return 0;
00189 }
00190
00191
00192
00199 static int check_block(overhead * ohp)
00200 {
00201 int rc1, rc2, rc3;
00202
00203 if ((rc1 = memscan(ohp->picket1, PICKET1, sizeof ohp->picket1)) != 0)
00204 dump_block(ohp, "corrupt pre-header fence");
00205 if ((rc2 = memscan(ohp->picket2, PICKET2, sizeof ohp->picket2)) != 0)
00206 dump_block(ohp, "corrupt post-header fence");
00207 if ((rc3 = memscan((char *)&ohp[1] + ohp->reqsz, PICKET3, PICKETSZ)) != 0)
00208 dump_block(ohp, "corrupt post-user fence");
00209
00210 assert(!rc1 && !rc2 && !rc3);
00211
00212 return !rc1 && !rc2 && !rc3 ? 1 : 0;
00213 }
00214
00215
00216
00217
00218
00219 void * dnxMalloc(size_t sz, char * file, int line)
00220 {
00221 overhead * ohp;
00222 size_t blksz = ALIGNSZ(sizeof *ohp + sz + PICKETSZ);
00223
00224 assert(sz);
00225 assert(file && line);
00226
00227 ohp = malloc(blksz);
00228 assert(ohp);
00229 if (!ohp) return NULL;
00230
00231 memset(ohp->picket1, PICKET1, sizeof ohp->picket1);
00232 ohp->next = 0;
00233 ohp->reqsz = sz;
00234 ohp->actualsz = blksz;
00235 ohp->file = strdup(file);
00236 ohp->line = line;
00237 memset(ohp->picket2, PICKET2, sizeof ohp->picket2);
00238
00239 memset(&ohp[1], ALLOCED, sz);
00240 memset((char *)&ohp[1] + sz, PICKET3, PICKETSZ);
00241 memset((char *)&ohp[1] + sz + PICKETSZ, ALIGNED,
00242 blksz - (sizeof *ohp + sz + PICKETSZ));
00243
00244 link_block(ohp);
00245
00246 dnxDebug(10, "dnxHeap: alloc(%ld) == %p.", sz, &ohp[1]);
00247
00248 return &ohp[1];
00249 }
00250
00251
00252
00253 void * dnxCalloc(size_t n, size_t sz, char * file, int line)
00254 {
00255 size_t blksz = n * sz;
00256 void * p;
00257
00258 assert(n && sz);
00259 assert(file && line);
00260
00261 p = dnxMalloc(blksz, file, line);
00262
00263 memset(p, 0, blksz);
00264
00265 return p;
00266 }
00267
00268
00269
00270 void * dnxRealloc(void * p, size_t sz, char * file, int line)
00271 {
00272 assert(p || sz);
00273 assert(file && line);
00274
00275 if (!sz)
00276 dnxFree(p), p = 0;
00277 else if (!p)
00278 p = dnxMalloc(sz, file, line);
00279 else
00280 {
00281 overhead * ohp = &((overhead *)p)[-1];
00282 void * np = dnxMalloc(sz, file, line);
00283 memcpy(np, p, sz < ohp->reqsz? sz: ohp->reqsz);
00284 dnxFree(p);
00285 p = np;
00286 }
00287 return p;
00288 }
00289
00290
00291
00292 char * dnxStrdup(char * str, char * file, int line)
00293 {
00294 char * s;
00295 size_t allocsz;
00296
00297 assert(str);
00298 assert(file && line);
00299
00300 allocsz = strlen(str) + 1;
00301
00302 if ((s = (char *)dnxMalloc(allocsz, file, line)) == 0)
00303 return 0;
00304
00305 memcpy(s, str, allocsz);
00306 return s;
00307 }
00308
00309
00310
00311 void dnxFree(void * p)
00312 {
00313 if (p)
00314 {
00315 overhead * ohp = &((overhead *)p)[-1];
00316 if (!unlink_block(ohp))
00317 {
00318 dnxDebug(1, "dnxHeap: free(%p) - attempt to free non-heap address.", p);
00319 assert(0);
00320 return;
00321 }
00322 if (!check_block(ohp))
00323 return;
00324 free(ohp->file);
00325 free(ohp);
00326 ohp = NULL;
00327 dnxDebug(10, "dnxHeap: free(%p).", p);
00328 p = NULL;
00329 }
00330 }
00331
00332
00333
00334 int dnxCheckHeap(void)
00335 {
00336 overhead * cp;
00337 pthread_mutex_lock(&list_lock);
00338 dnxDebug(1, "dnxCheckHeap: %d unfreed blocks remaining...", blkcnt);
00339 for (cp = head; cp; cp = cp->next)
00340 {
00341 dump_block(cp, "unfreed memory block");
00342 if (!check_block(cp))
00343 break;
00344 }
00345 pthread_mutex_unlock(&list_lock);
00346 return blkcnt? -1: 0;
00347 }
00348
00349
00350