]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/smartall.c
Fix bat crash due to alignment diff in bat and core code
[bacula/bacula] / bacula / src / lib / smartall.c
index 6261fffc6c121563508ea293a0ba20ed8e765829..acc27295aeb2615d1f17dd68a4d262fd7d5a8a5b 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
 
                          S M A R T A L L O C
 
 */
 
-/*
-   Copyright (C) 2000-2006 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
-   the file LICENSE for additional details.
-
- */
+#define _LOCKMGR_COMPLIANT
 
 #include "bacula.h"
 /* Use the real routines here */
@@ -79,6 +93,7 @@ struct abufhead {
    unsigned ablen;             /* Buffer length in bytes */
    const char *abfname;        /* File name pointer */
    sm_ushort ablineno;         /* Line number of allocation */
+   bool abin_use;              /* set when malloced and cleared when free */
 };
 
 static struct b_queue abqueue = {    /* Allocated buffer queue */
@@ -116,9 +131,10 @@ static void *smalloc(const char *fname, int lineno, unsigned int nbytes)
       qinsert(&abqueue, (struct b_queue *) buf);
       head->ablen = nbytes;
       head->abfname = bufimode ? NULL : fname;
-      head->ablineno = (sm_ushort) lineno;
+      head->ablineno = (sm_ushort)lineno;
+      head->abin_use = true;
       /* Emplace end-clobber detector at end of buffer */
-      buf[nbytes - 1] = (uint8_t)((((long) buf) & 0xFF) ^ 0xC5);
+      buf[nbytes - 1] = (uint8_t)((((intptr_t) buf) & 0xFF) ^ 0xC5);
       buf += HEAD_SIZE;  /* Increment to user data start */
       if (++sm_buffers > sm_max_buffers) {
          sm_max_buffers = sm_buffers;
@@ -148,6 +164,7 @@ void sm_new_owner(const char *fname, int lineno, char *buf)
    buf -= HEAD_SIZE;  /* Decrement to header */
    ((struct abufhead *)buf)->abfname = bufimode ? NULL : fname;
    ((struct abufhead *)buf)->ablineno = (sm_ushort) lineno;
+   ((struct abufhead *)buf)->abin_use = true;
    return;
 }
 
@@ -166,7 +183,7 @@ void sm_free(const char *file, int line, void *fp)
    }
 
    cp -= HEAD_SIZE;
-   qp = (struct b_queue *) cp;
+   qp = (struct b_queue *)cp;
    struct abufhead *head = (struct abufhead *)cp;
 
    P(mutex);
@@ -174,6 +191,12 @@ void sm_free(const char *file, int line, void *fp)
          head->ablen, fp,
          head->abfname, head->ablineno);
 
+   if (!head->abin_use) {
+      V(mutex);
+      Emsg2(M_ABORT, 0, _("double free from %s:%d\n"), file, line);
+   }
+   head->abin_use = false;
+
    /* The following assertions will catch virtually every release
       of an address which isn't an allocated buffer. */
    if (qp->qnext->qprev != qp) {
@@ -189,7 +212,7 @@ void sm_free(const char *file, int line, void *fp)
       allocated  space in the buffer by comparing the end of buffer
       checksum with the address of the buffer.  */
 
-   if (((unsigned char *)cp)[head->ablen - 1] != ((((long) cp) & 0xFF) ^ 0xC5)) {
+   if (((unsigned char *)cp)[head->ablen - 1] != ((((intptr_t) cp) & 0xFF) ^ 0xC5)) {
       V(mutex);
       Emsg2(M_ABORT, 0, _("Buffer overrun called from %s:%d\n"), file, line);
    }
@@ -205,9 +228,13 @@ void sm_free(const char *file, int line, void *fp)
       "designer  garbage"  (Duff  Kurland's  phrase) of alternating
       bits.  This is intended to ruin the day for any miscreant who
       attempts to access data through a pointer into storage that's
-      been previously released. */
+      been previously released.
 
-   memset(cp, 0xAA, (int) head->ablen);
+      Modified, kes May, 2007 to not zap the header. This allows us
+      to check the in_use bit and detect doubly freed buffers.
+   */
+
+   memset(cp+HEAD_SIZE, 0xAA, (int)(head->ablen - HEAD_SIZE));
 
    free(cp);
 }
@@ -270,14 +297,12 @@ void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
    /*  If  the  old  block  pointer  is  NULL, treat realloc() as a
       malloc().  SVID is silent  on  this,  but  many  C  libraries
       permit this.  */
-
    if (ptr == NULL) {
       return sm_malloc(fname, lineno, size);
    }
 
    /* If the old and new sizes are the same, be a nice guy and just
       return the buffer passed in.  */
-
    cp -= HEAD_SIZE;
    struct abufhead *head = (struct abufhead *)cp;
    osize = head->ablen - (HEAD_SIZE + 1);
@@ -294,7 +319,7 @@ void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
 // sm_bytes -= head->ablen;
 
    if ((buf = smalloc(fname, lineno, size)) != NULL) {
-      memcpy(buf, ptr, (int) sm_min(size, osize));
+      memcpy(buf, ptr, (int)sm_min(size, osize));
       /* If the new buffer is larger than the old, fill the balance
          of it with "designer garbage". */
       if (size > osize) {
@@ -302,7 +327,6 @@ void *sm_realloc(const char *fname, int lineno, void *ptr, unsigned int size)
       }
 
       /* All done.  Free and dechain the original buffer. */
-
       sm_free(__FILE__, __LINE__, ptr);
    }
    Dmsg4(150, _("sm_realloc %d at %x from %s:%d\n"), size, buf, fname, lineno);
@@ -353,7 +377,7 @@ void actuallyfree(void *cp)
  *  N.B. DO NOT USE any Bacula print routines (Dmsg, Jmsg, Emsg, ...)
  *    as they have all been shut down at this point.
  */
-void sm_dump(bool bufdump)
+void sm_dump(bool bufdump, bool in_use) 
 {
    struct abufhead *ap;
 
@@ -369,23 +393,24 @@ void sm_dump(bool bufdump)
          fprintf(stderr, _(
             "\nOrphaned buffers exist.  Dump terminated following\n"
             "  discovery of bad links in chain of orphaned buffers.\n"
-            "  Buffer address with bad links: %lx\n"), (long) ap);
+            "  Buffer address with bad links: %p\n"), ap);
          break;
       }
 
       if (ap->abfname != NULL) {
          unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
          char errmsg[500];
+         char *cp = ((char *)ap) + HEAD_SIZE;
 
          bsnprintf(errmsg, sizeof(errmsg),
-           _("Orphaned buffer:  %6u bytes allocated at line %d of %s %s\n"),
-            memsize, ap->ablineno, my_name, ap->abfname
+           _("%s buffer:  %s %6u bytes buf=%p allocated at %s:%d\n"),
+            in_use?"In use":"Orphaned",
+            my_name, memsize, cp, ap->abfname, ap->ablineno
          );
          fprintf(stderr, "%s", errmsg);
          if (bufdump) {
             char buf[20];
             unsigned llen = 0;
-            char *cp = ((char *) ap) + HEAD_SIZE;
 
             errmsg[0] = EOS;
             while (memsize) {
@@ -413,10 +438,10 @@ void sm_dump(bool bufdump)
 /*  SM_CHECK --  Check the buffers and dump if any damage exists. */
 void sm_check(const char *fname, int lineno, bool bufdump)
 {
-        if (!sm_check_rtn(fname, lineno, bufdump)) {
-           Emsg2(M_ABORT, 0, _("Damaged buffer found. Called from %s:%d\n"),
-              fname, lineno);
-        }
+   if (!sm_check_rtn(fname, lineno, bufdump)) {
+      Emsg2(M_ABORT, 0, _("Damaged buffer found. Called from %s:%d\n"),
+            fname, lineno);
+   }
 }
 
 #undef sm_check_rtn
@@ -428,18 +453,21 @@ int sm_check_rtn(const char *fname, int lineno, bool bufdump)
 
    P(mutex);
    ap = (struct abufhead *) abqueue.qnext;
-   while (ap != (struct abufhead *) &abqueue) {
+   while (ap != (struct abufhead *)&abqueue) {
       bad = 0;
-      if ((ap == NULL) ||
-          (ap->abq.qnext->qprev != (struct b_queue *) ap)) {
-         bad = 0x1;
-      }
-      if (ap->abq.qprev->qnext != (struct b_queue *) ap) {
-         bad |= 0x2;
-      }
-      if (((unsigned char *) ap)[((struct abufhead *) ap)->ablen - 1] !=
-           ((((long) ap) & 0xFF) ^ 0xC5)) {
-         bad |= 0x4;
+      if (ap != NULL) {
+         if (ap->abq.qnext->qprev != (struct b_queue *)ap) {
+            bad = 0x1;
+         }
+         if (ap->abq.qprev->qnext != (struct b_queue *)ap) {
+            bad |= 0x2;
+         }
+         if (((unsigned char *) ap)[((struct abufhead *)ap)->ablen - 1] !=
+              ((((intptr_t) ap) & 0xFF) ^ 0xC5)) {
+            bad |= 0x4;
+         }
+      } else {
+         bad = 0x8;
       }
       badbuf |= bad;
       if (bad) {
@@ -455,8 +483,14 @@ int sm_check_rtn(const char *fname, int lineno, bool bufdump)
          if (bad & 0x4) {
             fprintf(stderr, _("  discovery of data overrun.\n"));
          }
+         if (bad & 0x8) {
+            fprintf(stderr, _("  NULL pointer.\n"));
+         }
 
-         fprintf(stderr, _("  Buffer address: %lx\n"), (long) ap);
+         if (!ap) {
+            goto get_out;
+         }
+         fprintf(stderr, _("  Buffer address: %p\n"), ap);
 
          if (ap->abfname != NULL) {
             unsigned memsize = ap->ablen - (HEAD_SIZE + 1);
@@ -492,8 +526,9 @@ int sm_check_rtn(const char *fname, int lineno, bool bufdump)
             }
          }
       }
-      ap = (struct abufhead *) ap->abq.qnext;
+      ap = (struct abufhead *)ap->abq.qnext;
    }
+get_out:
    V(mutex);
    return badbuf ? 0 : 1;
 }
@@ -506,9 +541,9 @@ int sm_check_rtn(const char *fname, int lineno, bool bufdump)
                    that all the other safeguards still apply to  buffers
                    allocated  when  sm_static(1)  mode is in effect.  */
 
-void sm_static(int mode)
+void sm_static(bool mode)
 {
-   bufimode = (bool) (mode != 0);
+   bufimode = mode;
 }
 
 /*