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-2004 Kern Sibbald and John Walker
24 This program is free software; you can redistribute it and/or
25 modify it under the terms of the GNU General Public License as
26 published by the Free Software Foundation; either version 2 of
27 the License, or (at your option) any later version.
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 GNU
32 General Public License for more details.
34 You should have received a copy of the GNU General Public
35 License along with this program; if not, write to the Free
36 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
42 /* Use the real routines here */
48 /* We normally turn off debugging here.
49 * If you want it, simply #ifdef all the
57 #define Dmsg2(l,f,a1,a2)
58 #define Dmsg3(l,f,a1,a2,a3)
59 #define Dmsg4(l,f,a1,a2,a3,a4)
62 uint64_t sm_max_bytes = 0;
63 uint64_t sm_bytes = 0;
64 uint32_t sm_max_buffers = 0;
65 uint32_t sm_buffers = 0;
69 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
71 extern char my_name[]; /* daemon name */
73 typedef unsigned short sm_ushort;
75 #define EOS '\0' /* End of string sentinel */
76 #define sm_min(a, b) ((a) < (b) ? (a) : (b))
78 /* Queue data structures */
80 /* Memory allocation control structures and storage. */
83 struct b_queue abq; /* Links on allocated queue */
84 unsigned ablen; /* Buffer length in bytes */
85 const char *abfname; /* File name pointer */
86 sm_ushort ablineno; /* Line number of allocation */
89 static struct b_queue abqueue = { /* Allocated buffer queue */
94 static bool bufimode = false; /* Buffers not tracked when True */
96 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
99 /* SMALLOC -- Allocate buffer, enqueing on the orphaned buffer
102 static void *smalloc(const char *fname, int lineno, unsigned int nbytes)
106 /* Note: Unix MALLOC actually permits a zero length to be
107 passed and allocates a valid block with zero user bytes.
108 Such a block can later be expanded with realloc(). We
109 disallow this based on the belief that it's better to make
110 a special case and allocate one byte in the rare case this
111 is desired than to miss all the erroneous occurrences where
112 buffer length calculation code results in a zero. */
116 nbytes += HEAD_SIZE + 1;
117 if ((buf = (char *)malloc(nbytes)) != NULL) {
118 struct abufhead *head = (struct abufhead *)buf;
120 /* Enqueue buffer on allocated list */
121 qinsert(&abqueue, (struct b_queue *) buf);
122 head->ablen = nbytes;
123 head->abfname = bufimode ? NULL : fname;
124 head->ablineno = (sm_ushort) lineno;
125 /* Emplace end-clobber detector at end of buffer */
126 buf[nbytes - 1] = (((long) buf) & 0xFF) ^ 0xC5;
127 buf += HEAD_SIZE; /* Increment to user data start */
128 if (++sm_buffers > sm_max_buffers) {
129 sm_max_buffers = sm_buffers;
132 if (sm_bytes > sm_max_bytes) {
133 sm_max_bytes = sm_bytes;
137 Emsg0(M_ABORT, 0, _("Out of memory\n"));
139 Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno);
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);
197 sm_bytes -= head->ablen;
202 /* Now we wipe the contents of the just-released buffer with
203 "designer garbage" (Duff Kurland's phrase) of alternating
204 bits. This is intended to ruin the day for any miscreant who
205 attempts to access data through a pointer into storage that's
206 been previously released. */
208 memset(cp, 0xAA, (int) head->ablen);
213 /* SM_MALLOC -- Allocate buffer. NULL is returned if no memory
216 void *sm_malloc(const char *fname, int lineno, unsigned int nbytes)
220 if ((buf = smalloc(fname, lineno, nbytes)) != NULL) {
222 /* To catch sloppy code that assumes buffers obtained from
223 malloc() are zeroed, we preset the buffer contents to
224 "designer garbage" consisting of alternating bits. */
226 memset(buf, 0x55, (int) nbytes);
228 Emsg0(M_ABORT, 0, _("Out of memory\n"));
233 /* SM_CALLOC -- Allocate an array and clear it to zero. */
235 void *sm_calloc(const char *fname, int lineno,
236 unsigned int nelem, unsigned int elsize)
240 if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) {
241 memset(buf, 0, (int) (nelem * elsize));
243 Emsg0(M_ABORT, 0, _("Out of memory\n"));
248 /* SM_REALLOC -- Adjust the size of a previously allocated buffer.
249 Note that the trick of "resurrecting" a previously
250 freed buffer with realloc() is NOT supported by this
251 function. Further, because of the need to maintain
252 our control storage, SM_REALLOC must always allocate
253 a new block and copy the data in the old block.
254 This may result in programs which make heavy use of
255 realloc() running much slower than normally. */
257 void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
261 char *cp = (char *) ptr;
263 Dmsg4(400, "sm_realloc %s:%d 0x%x %d\n", fname, lineno, ptr, size);
265 e_msg(fname, lineno, M_ABORT, 0, "sm_realloc size: %d\n", size);
268 /* If the old block pointer is NULL, treat realloc() as a
269 malloc(). SVID is silent on this, but many C libraries
273 return sm_malloc(fname, lineno, size);
276 /* If the old and new sizes are the same, be a nice guy and just
277 return the buffer passed in. */
280 struct abufhead *head = (struct abufhead *)cp;
281 osize = head->ablen - (HEAD_SIZE + 1);
286 /* Sizes differ. Allocate a new buffer of the requested size.
287 If we can't obtain such a buffer, act as defined in SVID:
288 return NULL from realloc() and leave the buffer in PTR
294 if ((buf = smalloc(fname, lineno, size)) != NULL) {
295 memcpy(buf, ptr, (int) sm_min(size, osize));
296 /* If the new buffer is larger than the old, fill the balance
297 of it with "designer garbage". */
299 memset(((char *) buf) + osize, 0x55, (int) (size - osize));
302 /* All done. Free and dechain the original buffer. */
304 sm_free(__FILE__, __LINE__, ptr);
306 Dmsg4(150, "sm_realloc %d at %x from %s:%d\n", size, buf, fname, lineno);
310 /* ACTUALLYMALLOC -- Call the system malloc() function to obtain
311 storage which will eventually be released
312 by system or library routines not compiled
315 void *actuallymalloc(unsigned int size)
320 /* ACTUALLYCALLOC -- Call the system calloc() function to obtain
321 storage which will eventually be released
322 by system or library routines not compiled
325 void *actuallycalloc(unsigned int nelem, unsigned int elsize)
327 return calloc(nelem, elsize);
330 /* ACTUALLYREALLOC -- Call the system realloc() function to obtain
331 storage which will eventually be released
332 by system or library routines not compiled
335 void *actuallyrealloc(void *ptr, unsigned int size)
337 Dmsg2(400, "Actuallyrealloc 0x%x %d\n", ptr, size);
338 return realloc(ptr, size);
341 /* ACTUALLYFREE -- Interface to system free() function to release
342 buffers allocated by low-level routines. */
344 void actuallyfree(void *cp)
349 /* SM_DUMP -- Print orphaned buffers (and dump them if BUFDUMP is
351 * N.B. DO NOT USE any Bacula print routines (Dmsg, Jmsg, Emsg, ...)
352 * as they have all been shut down at this point.
354 void sm_dump(bool bufdump)
360 ap = (struct abufhead *)abqueue.qnext;
362 while (ap != (struct abufhead *) &abqueue) {
365 (ap->abq.qnext->qprev != (struct b_queue *) ap) ||
366 (ap->abq.qprev->qnext != (struct b_queue *) ap)) {
368 "\nOrphaned buffers exist. Dump terminated following\n");
370 " 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);