]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/smartall.c
Add wx-console directory
[bacula/bacula] / bacula / src / lib / smartall.c
1 /*
2
3                          S M A R T A L L O C
4                         Smart Memory Allocator
5
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:
13
14                   http://www.fourmilab.ch/smartall/
15
16   
17          Version $Id$
18
19 */
20
21 /*
22    Copyright (C) 2000-2004 Kern Sibbald and John Walker
23
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.
28
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.
33
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,
37    MA 02111-1307, USA.
38
39  */
40
41 #include "bacula.h"
42 /* Use the real routines here */
43 #undef realloc
44 #undef calloc
45 #undef malloc
46 #undef free
47
48 /* We normally turn off debugging here.
49  *  If you want it, simply #ifdef all the 
50  *  following off.
51  */
52 #undef Dmsg1
53 #undef Dmsg2
54 #undef Dmsg3
55 #undef Dmsg4
56 #define Dmsg1(l,f,a1)
57 #define Dmsg2(l,f,a1,a2)
58 #define Dmsg3(l,f,a1,a2,a3)
59 #define Dmsg4(l,f,a1,a2,a3,a4)
60       
61
62
63 #ifdef SMARTALLOC
64
65 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
66
67 extern char my_name[];                /* daemon name */
68
69 typedef unsigned short sm_ushort;
70
71 #define EOS      '\0'              /* End of string sentinel */
72 #define sm_min(a, b) ((a) < (b) ? (a) : (b))
73
74 /*  Queue data structures  */
75
76 /*  Memory allocation control structures and storage.  */
77
78 struct abufhead {
79    struct b_queue abq;         /* Links on allocated queue */
80    unsigned ablen;             /* Buffer length in bytes */
81    const char *abfname;        /* File name pointer */
82    sm_ushort ablineno;         /* Line number of allocation */ 
83 };
84
85 static struct b_queue abqueue = {    /* Allocated buffer queue */
86    &abqueue, &abqueue
87 };
88
89 static bool bufimode = false;   /* Buffers not tracked when True */
90
91 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
92
93
94 /*  SMALLOC  --  Allocate buffer, enqueing on the orphaned buffer
95                  tracking list.  */
96
97 static void *smalloc(const char *fname, int lineno, unsigned int nbytes)
98 {
99    char *buf;
100
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.  */
108
109    ASSERT(nbytes > 0);
110
111    nbytes += HEAD_SIZE + 1;
112    if ((buf = (char *)malloc(nbytes)) != NULL) {
113       P(mutex);
114       /* Enqueue buffer on allocated list */
115       qinsert(&abqueue, (struct b_queue *) buf);
116       ((struct abufhead *) buf)->ablen = nbytes;
117       ((struct abufhead *) buf)->abfname = bufimode ? NULL : fname;
118       ((struct abufhead *) buf)->ablineno = (sm_ushort) lineno;
119       /* Emplace end-clobber detector at end of buffer */
120       buf[nbytes - 1] = (((long) buf) & 0xFF) ^ 0xC5;
121       buf += HEAD_SIZE;  /* Increment to user data start */
122       V(mutex);
123    } else {
124       Emsg0(M_ABORT, 0, _("Out of memory\n"));
125    }
126    Dmsg4(1150, "smalloc %d at %x from %s:%d\n", nbytes, buf, fname, lineno);
127    return (void *)buf;
128 }
129
130 /*  SM_NEW_OWNER -- Update the File and line number for a buffer
131                     This is to accomodate mem_pool. */
132
133 void sm_new_owner(const char *fname, int lineno, char *buf)
134 {
135    buf -= HEAD_SIZE;  /* Decrement to header */
136    ((struct abufhead *)buf)->abfname = bufimode ? NULL : fname;
137    ((struct abufhead *)buf)->ablineno = (sm_ushort) lineno;
138    return;
139 }
140
141 /*  SM_FREE  --  Update free pool availability.  FREE is never called
142                  except  through  this interface or by actuallyfree().
143                  free(x)  is  defined  to  generate  a  call  to  this
144                  routine.  */
145
146 void sm_free(const char *file, int line, void *fp)
147 {
148    char *cp = (char *) fp;
149    struct b_queue *qp;
150
151    if (cp == NULL) {
152       Emsg2(M_ABORT, 0, "Attempt to free NULL called from %s:%d\n", file, line);
153    }
154
155    cp -= HEAD_SIZE;
156    qp = (struct b_queue *) cp;
157
158    P(mutex);
159    Dmsg4(1150, "sm_free %d at %x from %s:%d\n", 
160          ((struct abufhead *)cp)->ablen, fp, 
161          ((struct abufhead *)cp)->abfname, ((struct abufhead *)cp)->ablineno);
162
163    /* The following assertions will catch virtually every release
164       of an address which isn't an allocated buffer. */
165    if (qp->qnext->qprev != qp) {
166       V(mutex);
167       Emsg2(M_ABORT, 0, "qp->qnext->qprev != qp called from %s:%d\n", file, line);
168    }
169    if (qp->qprev->qnext != qp) {
170       V(mutex);
171       Emsg2(M_ABORT, 0, "qp->qprev->qnext != qp called from %s:%d\n", file, line);
172    }
173
174    /* The following assertion detects storing off the  end  of  the
175       allocated  space in the buffer by comparing the end of buffer
176       checksum with the address of the buffer.  */
177
178    if (((unsigned char *) cp)[((struct abufhead *) cp)->ablen - 1] !=
179             ((((long) cp) & 0xFF) ^ 0xC5)) {
180       V(mutex);
181       Emsg2(M_ABORT, 0, "Buffer overrun called from %s:%d\n", file, line);
182    }
183
184
185    qdchain(qp);
186    V(mutex);
187
188    /* Now we wipe the contents of  the  just-released  buffer  with
189       "designer  garbage"  (Duff  Kurland's  phrase) of alternating
190       bits.  This is intended to ruin the day for any miscreant who
191       attempts to access data through a pointer into storage that's
192       been previously released. */
193
194    memset(cp, 0xAA, (int) ((struct abufhead *) cp)->ablen);
195
196    free(cp);
197 }
198
199 /*  SM_MALLOC  --  Allocate buffer.  NULL is returned if no memory
200                    was available.  */
201
202 void *sm_malloc(const char *fname, int lineno, unsigned int nbytes)
203 {
204    void *buf;
205
206    if ((buf = smalloc(fname, lineno, nbytes)) != NULL) {
207
208       /* To catch sloppy code that assumes  buffers  obtained  from
209          malloc()  are  zeroed,  we  preset  the buffer contents to
210          "designer garbage" consisting of alternating bits.  */
211
212       memset(buf, 0x55, (int) nbytes);
213    } else {
214       Emsg0(M_ABORT, 0, _("Out of memory\n"));
215    }
216    return buf;
217 }
218
219 /*  SM_CALLOC  --  Allocate an array and clear it to zero.  */
220
221 void *sm_calloc(const char *fname, int lineno,
222                 unsigned int nelem, unsigned int elsize)
223 {
224    void *buf;
225
226    if ((buf = smalloc(fname, lineno, nelem * elsize)) != NULL) {
227       memset(buf, 0, (int) (nelem * elsize));
228    } else {
229       Emsg0(M_ABORT, 0, _("Out of memory\n"));
230    }
231    return buf;
232 }
233
234 /*  SM_REALLOC  --  Adjust the size of a  previously  allocated  buffer.
235                     Note  that  the trick of "resurrecting" a previously
236                     freed buffer with realloc() is NOT supported by this
237                     function.   Further, because of the need to maintain
238                     our control storage, SM_REALLOC must always allocate
239                     a  new  block  and  copy  the data in the old block.
240                     This may result in programs which make heavy use  of
241                     realloc() running much slower than normally.  */
242
243 void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
244 {
245    unsigned osize;
246    void *buf;
247    char *cp = (char *) ptr;
248
249    Dmsg4(400, "sm_realloc %s:%d 0x%x %d\n", fname, lineno, ptr, size);
250    if (size <= 0) {
251       e_msg(fname, lineno, M_ABORT, 0, "sm_realloc size: %d\n", size);
252    }
253
254    /*  If  the  old  block  pointer  is  NULL, treat realloc() as a
255       malloc().  SVID is silent  on  this,  but  many  C  libraries
256       permit this.  */
257
258    if (ptr == NULL) {
259       return sm_malloc(fname, lineno, size);
260    }
261
262    /* If the old and new sizes are the same, be a nice guy and just
263       return the buffer passed in.  */
264
265    cp -= HEAD_SIZE;
266    osize = ((struct abufhead *) cp)->ablen - (HEAD_SIZE + 1);
267    if (size == osize) {
268       return ptr;
269    }
270
271    /* Sizes differ.  Allocate a new buffer of the  requested  size.
272       If  we  can't  obtain  such a buffer, act as defined in SVID:
273       return NULL from  realloc()  and  leave  the  buffer  in  PTR
274       intact.  */
275
276    if ((buf = smalloc(fname, lineno, size)) != NULL) {
277       memcpy(buf, ptr, (int) sm_min(size, osize));
278       /* If the new buffer is larger than the old, fill the balance
279          of it with "designer garbage". */
280       if (size > osize) {
281          memset(((char *) buf) + osize, 0x55, (int) (size - osize));
282       }
283
284       /* All done.  Free and dechain the original buffer. */
285
286       sm_free(__FILE__, __LINE__, ptr);
287    }
288    Dmsg4(150, "sm_realloc %d at %x from %s:%d\n", size, buf, fname, lineno);
289    return buf;
290 }
291
292 /*  ACTUALLYMALLOC  --  Call the system malloc() function to obtain
293                         storage which will eventually be released
294                         by system or library routines not compiled
295                         using SMARTALLOC.  */
296
297 void *actuallymalloc(unsigned int size)
298 {
299    return malloc(size);
300 }
301
302 /*  ACTUALLYCALLOC  --  Call the system calloc() function to obtain
303                         storage which will eventually be released
304                         by system or library routines not compiled
305                         using SMARTALLOC.  */
306
307 void *actuallycalloc(unsigned int nelem, unsigned int elsize)
308 {
309    return calloc(nelem, elsize);
310 }
311
312 /*  ACTUALLYREALLOC  --  Call the system realloc() function to obtain
313                          storage which will eventually be released
314                          by system or library routines not compiled
315                          using SMARTALLOC.  */
316
317 void *actuallyrealloc(void *ptr, unsigned int size)
318 {
319    Dmsg2(400, "Actuallyrealloc 0x%x %d\n", ptr, size);
320    return realloc(ptr, size);
321 }
322
323 /*  ACTUALLYFREE  --  Interface to system free() function to release
324                       buffers allocated by low-level routines. */
325
326 void actuallyfree(void *cp)
327 {
328    free(cp);
329 }
330
331 /*  SM_DUMP  --  Print orphaned buffers (and dump them if BUFDUMP is
332  *               True).
333  *  N.B. DO NOT USE any Bacula print routines (Dmsg, Jmsg, Emsg, ...)
334  *    as they have all been shut down at this point.
335  */
336 void sm_dump(bool bufdump)
337 {
338    struct abufhead *ap;
339
340    P(mutex);
341
342    ap = (struct abufhead *)abqueue.qnext;
343
344    while (ap != (struct abufhead *) &abqueue) {
345
346       if ((ap == NULL) ||
347           (ap->abq.qnext->qprev != (struct b_queue *) ap) || 
348           (ap->abq.qprev->qnext != (struct b_queue *) ap)) {
349          fprintf(stderr,
350             "\nOrphaned buffers exist.  Dump terminated following\n");
351          fprintf(stderr,
352             "  discovery of bad links in chain of orphaned buffers.\n");
353          fprintf(stderr,
354             "  Buffer address with bad links: %lx\n", (long) ap);
355          break;
356       }
357
358       if (ap->abfname != NULL) {
359          unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
360          char errmsg[500];
361
362          bsnprintf(errmsg, sizeof(errmsg),
363            "Orphaned buffer:  %6u bytes allocated at line %d of %s %s\n",
364             memsize, ap->ablineno, my_name, ap->abfname
365          );
366          fprintf(stderr, "%s", errmsg);
367          if (bufdump) {
368             char buf[20];
369             unsigned llen = 0;
370             char *cp = ((char *) ap) + HEAD_SIZE;
371
372             errmsg[0] = EOS;
373             while (memsize) {
374                if (llen >= 16) {
375                   bstrncat(errmsg, "\n", sizeof(errmsg));
376                   llen = 0;
377                   fprintf(stderr, "%s", errmsg);
378                   errmsg[0] = EOS;
379                }
380                bsnprintf(buf, sizeof(buf), " %02X",
381                   (*cp++) & 0xFF);
382                bstrncat(errmsg, buf, sizeof(errmsg));
383                llen++;
384                memsize--;
385             }
386             fprintf(stderr, "%s\n", errmsg);
387          }
388       }
389       ap = (struct abufhead *) ap->abq.qnext;
390    }
391    V(mutex);
392 }
393
394 #undef sm_check
395 /*  SM_CHECK --  Check the buffers and dump if any damage exists. */
396 void sm_check(const char *fname, int lineno, bool bufdump)
397 {
398         if (!sm_check_rtn(fname, lineno, bufdump)) {
399            Emsg2(M_ABORT, 0, "Damaged buffer found. Called from %s:%d\n",
400               fname, lineno);
401         }
402 }
403
404 #undef sm_check_rtn
405 /*  SM_CHECK_RTN -- Check the buffers and return 1 if OK otherwise 0 */
406 int sm_check_rtn(const char *fname, int lineno, bool bufdump)
407 {
408    struct abufhead *ap;
409    int bad, badbuf = 0;
410
411    P(mutex);
412    ap = (struct abufhead *) abqueue.qnext;
413    while (ap != (struct abufhead *) &abqueue) {
414       bad = 0;
415       if ((ap == NULL) ||
416           (ap->abq.qnext->qprev != (struct b_queue *) ap)) {
417          bad = 0x1;
418       }
419       if (ap->abq.qprev->qnext != (struct b_queue *) ap) { 
420          bad |= 0x2;
421       }
422       if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] !=
423            ((((long) ap) & 0xFF) ^ 0xC5)) {
424          bad |= 0x4;
425       }
426       badbuf |= bad;
427       if (bad) {
428          fprintf(stderr,
429             "\nDamaged buffers found at %s:%d\n", fname, lineno);
430
431          if (bad & 0x1) {
432             fprintf(stderr, "  discovery of bad prev link.\n");
433          }
434          if (bad & 0x2) {
435             fprintf(stderr, "  discovery of bad next link.\n");
436          }
437          if (bad & 0x4) {
438             fprintf(stderr, "  discovery of data overrun.\n");
439          }
440
441          fprintf(stderr, "  Buffer address: %lx\n", (long) ap);
442
443          if (ap->abfname != NULL) {
444             unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
445             char errmsg[80];
446
447             fprintf(stderr,
448               "Damaged buffer:  %6u bytes allocated at line %d of %s %s\n",
449                memsize, ap->ablineno, my_name, ap->abfname
450             );
451             if (bufdump) {
452                unsigned llen = 0;
453                char *cp = ((char *) ap) + HEAD_SIZE;
454
455                errmsg[0] = EOS;
456                while (memsize) {
457                   if (llen >= 16) {
458                      strcat(errmsg, "\n");
459                      llen = 0;
460                      fprintf(stderr, "%s", errmsg);
461                      errmsg[0] = EOS;
462                   }
463                   if (*cp < 0x20) {
464                      sprintf(errmsg + strlen(errmsg), " %02X",
465                         (*cp++) & 0xFF);
466                   } else {
467                      sprintf(errmsg + strlen(errmsg), " %c ",
468                         (*cp++) & 0xFF);
469                   }
470                   llen++;
471                   memsize--;
472                }
473                fprintf(stderr, "%s\n", errmsg);
474             }
475          }
476       }
477       ap = (struct abufhead *) ap->abq.qnext;
478    }
479    V(mutex);
480    return badbuf ? 0 : 1;
481 }
482
483
484 /*  SM_STATIC  --  Orphaned buffer detection can be disabled  (for  such
485                    items  as buffers allocated during initialisation) by
486                    calling   sm_static(1).    Normal   orphaned   buffer
487                    detection  can be re-enabled with sm_static(0).  Note
488                    that all the other safeguards still apply to  buffers
489                    allocated  when  sm_static(1)  mode is in effect.  */
490
491 void sm_static(int mode)
492 {
493    bufimode = (bool) (mode != 0);
494 }
495
496 /* 
497  * Here we overload C++'s global new and delete operators
498  *  so that the memory is allocated through smartalloc.
499  */
500
501 #ifdef xxx
502 void * operator new(size_t size)
503 {
504 // Dmsg1(000, "new called %d\n", size);
505    return sm_malloc(__FILE__, __LINE__, size);
506 }
507
508 void operator delete(void *buf)
509 {
510 // Dmsg1(000, "free called 0x%x\n", buf);
511    sm_free(__FILE__, __LINE__, buf);
512 }
513 #endif
514
515 #endif