- char *cp = (char *) fp;
- struct b_queue *qp;
-
- sm_check(__FILE__, __LINE__, True);
- if (cp == NULL) {
- Emsg2(M_ABORT, 0, "Attempt to free NULL called from %s:%d\n", file, line);
- }
-
- cp -= HEAD_SIZE;
- qp = (struct b_queue *) cp;
-
- Dmsg4(1150, "sm_free %d at %x from %s:%d\n",
- ((struct abufhead *)cp)->ablen, fp,
- ((struct abufhead *)cp)->abfname, ((struct abufhead *)cp)->ablineno);
-
- /* The following assertions will catch virtually every release
- of an address which isn't an allocated buffer. */
- if (qp->qnext->qprev != qp) {
- Emsg2(M_ABORT, 0, "qp->qnext->qprev != qp called from %s:%d\n", file, line);
- }
- if (qp->qprev->qnext != qp) {
- Emsg2(M_ABORT, 0, "qp->qprev->qnext != qp called from %s:%d\n", file, line);
- }
-
- /* The following assertion detects storing off the end of the
- allocated space in the buffer by comparing the end of buffer
- checksum with the address of the buffer. */
-
- if (((unsigned char *) cp)[((struct abufhead *) cp)->ablen - 1] !=
- ((((long) cp) & 0xFF) ^ 0xC5)) {
- Emsg2(M_ABORT, 0, "Buffer overrun called from %s:%d\n", file, line);
- }
-
-
- qdchain(qp);
-
- /* Now we wipe the contents of the just-released buffer with
- "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. */
-
- memset(cp, 0xAA, (int) ((struct abufhead *) cp)->ablen);
-
- free(cp);
+ char *cp = (char *) fp;
+ struct b_queue *qp;
+ uint32_t lineno = line;
+
+ if (cp == NULL) {
+ Emsg2(M_ABORT, 0, _("Attempt to free NULL called from %s:%d\n"), file, lineno);
+ }
+
+ cp -= HEAD_SIZE;
+ qp = (struct b_queue *)cp;
+ struct abufhead *head = (struct abufhead *)cp;
+
+ P(mutex);
+ Dmsg4(1150, "sm_free %d at %p from %s:%d\n",
+ head->ablen, fp,
+ head->abfname, head->ablineno);
+
+ if (!head->abin_use) {
+ V(mutex);
+ Emsg2(M_ABORT, 0, _("double free from %s:%d\n"), file, lineno);
+ }
+ 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) {
+ V(mutex);
+ Emsg2(M_ABORT, 0, _("qp->qnext->qprev != qp called from %s:%d\n"), file, lineno);
+ }
+ if (qp->qprev->qnext != qp) {
+ V(mutex);
+ Emsg2(M_ABORT, 0, _("qp->qprev->qnext != qp called from %s:%d\n"), file, lineno);
+ }
+
+ /* The following assertion detects storing off the end of the
+ 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] != ((((intptr_t) cp) & 0xFF) ^ 0xC5)) {
+ V(mutex);
+ Dmsg4(0, "Overrun buffer: len=%d addr=%p allocated: %s:%d\n",
+ head->ablen, fp,
+ head->abfname, head->ablineno);
+ Emsg2(M_ABORT, 0, _("Buffer overrun called from %s:%d\n"), file, line);
+ }
+ if (sm_buffers > 0) {
+ sm_buffers--;
+ sm_bytes -= head->ablen;
+ }
+
+ qdchain(qp);
+ V(mutex);
+
+ /* Now we wipe the contents of the just-released buffer with
+ "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.
+
+ 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);