6 Evolved over several years, starting with the initial
7 SMARTALLOC code for AutoSketch in 1986, guided by the Blind
8 Watchbreaker, John Walker. Isolated in this general-purpose
9 form in September of 1989. Updated with be more POSIX
10 compliant and to include Web-friendly HTML documentation in
11 October of 1998 by the same culprit. For additional
12 information and the current version visit the Web page:
14 http://www.fourmilab.ch/smartall/
22 Copyright (C) 2000-2006 Kern Sibbald
24 This program is free software; you can redistribute it and/or
25 modify it under the terms of the GNU General Public License
26 version 2 as amended with additional clauses defined in the
27 file LICENSE in the main source directory.
29 This program is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 the file LICENSE for additional details.
37 /* Use the real routines here */
43 /* We normally turn off debugging here.
44 * If you want it, simply #ifdef all the
52 #define Dmsg2(l,f,a1,a2)
53 #define Dmsg3(l,f,a1,a2,a3)
54 #define Dmsg4(l,f,a1,a2,a3,a4)
57 uint64_t sm_max_bytes = 0;
58 uint64_t sm_bytes = 0;
59 uint32_t sm_max_buffers = 0;
60 uint32_t sm_buffers = 0;
64 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
66 extern char my_name[]; /* daemon name */
68 typedef unsigned short sm_ushort;
70 #define EOS '\0' /* End of string sentinel */
71 #define sm_min(a, b) ((a) < (b) ? (a) : (b))
73 /* Queue data structures */
75 /* Memory allocation control structures and storage. */
78 struct b_queue abq; /* Links on allocated queue */
79 unsigned ablen; /* Buffer length in bytes */
80 const char *abfname; /* File name pointer */
81 sm_ushort ablineno; /* Line number of allocation */
84 static struct b_queue abqueue = { /* Allocated buffer queue */
89 static bool bufimode = false; /* Buffers not tracked when True */
91 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
94 /* SMALLOC -- Allocate buffer, enqueing on the orphaned buffer
97 static void *smalloc(const char *fname, int lineno, unsigned int nbytes)
101 /* Note: Unix MALLOC actually permits a zero length to be
102 passed and allocates a valid block with zero user bytes.
103 Such a block can later be expanded with realloc(). We
104 disallow this based on the belief that it's better to make
105 a special case and allocate one byte in the rare case this
106 is desired than to miss all the erroneous occurrences where
107 buffer length calculation code results in a zero. */
111 nbytes += HEAD_SIZE + 1;
112 if ((buf = (char *)malloc(nbytes)) != NULL) {
113 struct abufhead *head = (struct abufhead *)buf;
115 /* Enqueue buffer on allocated list */
116 qinsert(&abqueue, (struct b_queue *) buf);
117 head->ablen = nbytes;
118 head->abfname = bufimode ? NULL : fname;
119 head->ablineno = (sm_ushort) lineno;
120 /* Emplace end-clobber detector at end of buffer */
121 buf[nbytes - 1] = (uint8_t)((((long) buf) & 0xFF) ^ 0xC5);
122 buf += HEAD_SIZE; /* Increment to user data start */
123 if (++sm_buffers > sm_max_buffers) {
124 sm_max_buffers = sm_buffers;
127 if (sm_bytes > sm_max_bytes) {
128 sm_max_bytes = sm_bytes;
132 Emsg0(M_ABORT, 0, _("Out of memory\n"));
134 Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno);
135 #if SMALLOC_SANITY_CHECK > 0
136 if (sm_bytes > SMALLOC_SANITY_CHECK) {
137 Emsg0(M_ABORT, 0, _("Too much memory used."));
143 /* SM_NEW_OWNER -- Update the File and line number for a buffer
144 This is to accomodate mem_pool. */
146 void sm_new_owner(const char *fname, int lineno, char *buf)
148 buf -= HEAD_SIZE; /* Decrement to header */
149 ((struct abufhead *)buf)->abfname = bufimode ? NULL : fname;
150 ((struct abufhead *)buf)->ablineno = (sm_ushort) lineno;
154 /* SM_FREE -- Update free pool availability. FREE is never called
155 except through this interface or by actuallyfree().
156 free(x) is defined to generate a call to this
159 void sm_free(const char *file, int line, void *fp)
161 char *cp = (char *) fp;
165 Emsg2(M_ABORT, 0, _("Attempt to free NULL called from %s:%d\n"), file, line);
169 qp = (struct b_queue *) cp;
170 struct abufhead *head = (struct abufhead *)cp;
173 Dmsg4(1150, "sm_free %d at %x from %s:%d\n",
175 head->abfname, head->ablineno);
177 /* The following assertions will catch virtually every release
178 of an address which isn't an allocated buffer. */
179 if (qp->qnext->qprev != qp) {
181 Emsg2(M_ABORT, 0, _("qp->qnext->qprev != qp called from %s:%d\n"), file, line);
183 if (qp->qprev->qnext != qp) {
185 Emsg2(M_ABORT, 0, _("qp->qprev->qnext != qp called from %s:%d\n"), file, line);
188 /* The following assertion detects storing off the end of the
189 allocated space in the buffer by comparing the end of buffer
190 checksum with the address of the buffer. */
192 if (((unsigned char *)cp)[head->ablen - 1] != ((((long) cp) & 0xFF) ^ 0xC5)) {
194 Emsg2(M_ABORT, 0, _("Buffer overrun called from %s:%d\n"), file, line);
196 if (sm_buffers > 0) {
198 sm_bytes -= head->ablen;
204 /* Now we wipe the contents of the just-released buffer with
205 "designer garbage" (Duff Kurland's phrase) of alternating
206 bits. This is intended to ruin the day for any miscreant who
207 attempts to access data through a pointer into storage that's
208 been previously released. */
210 memset(cp, 0xAA, (int) head->ablen);
215 /* SM_MALLOC -- Allocate buffer. NULL is returned if no memory
218 void *sm_malloc(const char *fname, int lineno, unsigned int nbytes)
222 if ((buf = smalloc(fname, lineno, nbytes)) != NULL) {
224 /* To catch sloppy code that assumes buffers obtained from
225 malloc() are zeroed, we preset the buffer contents to
226 "designer garbage" consisting of alternating bits. */
228 memset(buf, 0x55, (int) nbytes);
230 Emsg0(M_ABORT, 0, _("Out of memory\n"));
235 /* SM_CALLOC -- Allocate an array and clear it to zero. */
237 void *sm_calloc(const char *fname, int lineno,
238 unsigned int nelem, unsigned int elsize)
242 if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) {
243 memset(buf, 0, (int) (nelem * elsize));
245 Emsg0(M_ABORT, 0, _("Out of memory\n"));
250 /* SM_REALLOC -- Adjust the size of a previously allocated buffer.
251 Note that the trick of "resurrecting" a previously
252 freed buffer with realloc() is NOT supported by this
253 function. Further, because of the need to maintain
254 our control storage, SM_REALLOC must always allocate
255 a new block and copy the data in the old block.
256 This may result in programs which make heavy use of
257 realloc() running much slower than normally. */
259 void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
263 char *cp = (char *) ptr;
265 Dmsg4(400, "sm_realloc %s:%d 0x%x %d\n", fname, lineno, ptr, size);
267 e_msg(fname, lineno, M_ABORT, 0, _("sm_realloc size: %d\n"), size);
270 /* If the old block pointer is NULL, treat realloc() as a
271 malloc(). SVID is silent on this, but many C libraries
275 return sm_malloc(fname, lineno, size);
278 /* If the old and new sizes are the same, be a nice guy and just
279 return the buffer passed in. */
282 struct abufhead *head = (struct abufhead *)cp;
283 osize = head->ablen - (HEAD_SIZE + 1);
288 /* Sizes differ. Allocate a new buffer of the requested size.
289 If we can't obtain such a buffer, act as defined in SVID:
290 return NULL from realloc() and leave the buffer in PTR
294 // sm_bytes -= head->ablen;
296 if ((buf = smalloc(fname, lineno, size)) != NULL) {
297 memcpy(buf, ptr, (int) sm_min(size, osize));
298 /* If the new buffer is larger than the old, fill the balance
299 of it with "designer garbage". */
301 memset(((char *) buf) + osize, 0x55, (int) (size - osize));
304 /* All done. Free and dechain the original buffer. */
306 sm_free(__FILE__, __LINE__, ptr);
308 Dmsg4(150, _("sm_realloc %d at %x from %s:%d\n"), size, buf, fname, lineno);
312 /* ACTUALLYMALLOC -- Call the system malloc() function to obtain
313 storage which will eventually be released
314 by system or library routines not compiled
317 void *actuallymalloc(unsigned int size)
322 /* ACTUALLYCALLOC -- Call the system calloc() function to obtain
323 storage which will eventually be released
324 by system or library routines not compiled
327 void *actuallycalloc(unsigned int nelem, unsigned int elsize)
329 return calloc(nelem, elsize);
332 /* ACTUALLYREALLOC -- Call the system realloc() function to obtain
333 storage which will eventually be released
334 by system or library routines not compiled
337 void *actuallyrealloc(void *ptr, unsigned int size)
339 Dmsg2(400, "Actuallyrealloc 0x%x %d\n", ptr, size);
340 return realloc(ptr, size);
343 /* ACTUALLYFREE -- Interface to system free() function to release
344 buffers allocated by low-level routines. */
346 void actuallyfree(void *cp)
351 /* SM_DUMP -- Print orphaned buffers (and dump them if BUFDUMP is
353 * N.B. DO NOT USE any Bacula print routines (Dmsg, Jmsg, Emsg, ...)
354 * as they have all been shut down at this point.
356 void sm_dump(bool bufdump)
362 ap = (struct abufhead *)abqueue.qnext;
364 while (ap != (struct abufhead *) &abqueue) {
367 (ap->abq.qnext->qprev != (struct b_queue *) ap) ||
368 (ap->abq.qprev->qnext != (struct b_queue *) ap)) {
370 "\nOrphaned buffers exist. Dump terminated following\n"
371 " discovery of bad links in chain of orphaned buffers.\n"
372 " Buffer address with bad links: %lx\n"), (long) ap);
376 if (ap->abfname != NULL) {
377 unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
380 bsnprintf(errmsg, sizeof(errmsg),
381 _("Orphaned buffer: %6u bytes allocated at line %d of %s %s\n"),
382 memsize, ap->ablineno, my_name, ap->abfname
384 fprintf(stderr, "%s", errmsg);
388 char *cp = ((char *) ap) + HEAD_SIZE;
393 bstrncat(errmsg, "\n", sizeof(errmsg));
395 fprintf(stderr, "%s", errmsg);
398 bsnprintf(buf, sizeof(buf), " %02X",
400 bstrncat(errmsg, buf, sizeof(errmsg));
404 fprintf(stderr, "%s\n", errmsg);
407 ap = (struct abufhead *) ap->abq.qnext;
413 /* SM_CHECK -- Check the buffers and dump if any damage exists. */
414 void sm_check(const char *fname, int lineno, bool bufdump)
416 if (!sm_check_rtn(fname, lineno, bufdump)) {
417 Emsg2(M_ABORT, 0, _("Damaged buffer found. Called from %s:%d\n"),
423 /* SM_CHECK_RTN -- Check the buffers and return 1 if OK otherwise 0 */
424 int sm_check_rtn(const char *fname, int lineno, bool bufdump)
430 ap = (struct abufhead *) abqueue.qnext;
431 while (ap != (struct abufhead *) &abqueue) {
434 (ap->abq.qnext->qprev != (struct b_queue *) ap)) {
437 if (ap->abq.qprev->qnext != (struct b_queue *) ap) {
440 if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] !=
441 ((((long) ap) & 0xFF) ^ 0xC5)) {
447 _("\nDamaged buffers found at %s:%d\n"), fname, lineno);
450 fprintf(stderr, _(" discovery of bad prev link.\n"));
453 fprintf(stderr, _(" discovery of bad next link.\n"));
456 fprintf(stderr, _(" discovery of data overrun.\n"));
459 fprintf(stderr, _(" Buffer address: %lx\n"), (long) ap);
461 if (ap->abfname != NULL) {
462 unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
466 _("Damaged buffer: %6u bytes allocated at line %d of %s %s\n"),
467 memsize, ap->ablineno, my_name, ap->abfname
471 char *cp = ((char *) ap) + HEAD_SIZE;
476 strcat(errmsg, "\n");
478 fprintf(stderr, "%s", errmsg);
482 sprintf(errmsg + strlen(errmsg), " %02X",
485 sprintf(errmsg + strlen(errmsg), " %c ",
491 fprintf(stderr, "%s\n", errmsg);
495 ap = (struct abufhead *) ap->abq.qnext;
498 return badbuf ? 0 : 1;
502 /* SM_STATIC -- Orphaned buffer detection can be disabled (for such
503 items as buffers allocated during initialisation) by
504 calling sm_static(1). Normal orphaned buffer
505 detection can be re-enabled with sm_static(0). Note
506 that all the other safeguards still apply to buffers
507 allocated when sm_static(1) mode is in effect. */
509 void sm_static(int mode)
511 bufimode = (bool) (mode != 0);
515 * Here we overload C++'s global new and delete operators
516 * so that the memory is allocated through smartalloc.
520 void * operator new(size_t size)
522 // Dmsg1(000, "new called %d\n", size);
523 return sm_malloc(__FILE__, __LINE__, size);
526 void operator delete(void *buf)
528 // Dmsg1(000, "free called 0x%x\n", buf);
529 sm_free(__FILE__, __LINE__, buf);