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