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