blob: f8071ced6a41fec31916c53888fae9c3c56c40a6 [file] [log] [blame]
#include <memcheck.h>
/*
* Copyright (C) 2008 Randall R. Stewart
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
the SCTP reference implementation is distributed in the hope that it
will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
************************
Please send any bug reports or fixes you make to one of the following email
addresses:
rrs@lakerest.net
Any bugs reported given to us we will try to fix... any fixes shared will
be incorperated into the next SCTP release.
There are still LOTS of bugs in this code... I always run on the motto
"it is a wonder any code ever works :)"
*/
#define MEMORY_PADDING 96
#define PADDING_HALF 48
#define MARKA 0xf1018810
#define MARKB 0xf1014410
struct memLinks {
uint32_t markA;
uint32_t markB;
uint32_t csum;
int usedFree;
size_t size;
size_t req;
struct memLinks *next;
struct memLinks *nextFree;
char *powner;
char *owner;
int bpowner;
int bowner;
u_char data[8];
};
static int countOf32 = 0;
static struct memLinks *free32 = 0;
static struct memLinks *head32 = 0;
static int countOf64 = 0;
static struct memLinks *free64 = 0;
static struct memLinks *head64 = 0;
static int countOf128 = 0;
static struct memLinks *free128 = 0;
static struct memLinks *head128 = 0;
static int countOf512 = 0;
static struct memLinks *free512 = 0;
static struct memLinks *head512 = 0;
static int countOf1024 = 0;
static struct memLinks *free1024 = 0;
static struct memLinks *head1024 = 0;
static u_long highest = 0;
static int memory_inited = 0;
static u_long lowest = 0xfffffff;
/*static pthread_mutex_t mu;*/
void
initMemoryLock()
{
/* pthread_mutex_init(&mu,NULL); */
memory_inited = 1;
}
void
verifyMemoryOf(struct memLinks *at)
{
unsigned int i, s;
s = 0;
for (i = 0; i < (at->size - sizeof(struct memLinks)); i++) {
s += (uint8_t)at->data[i];
}
if (s != at->csum) {
DEBUG_PRINTF("memcheck:usedFree:%d,size:%d req:%d powner:%s:%d owner:%s:%d sum:%x c:%x\n",
at->usedFree,
(int)at->size,
(int)at->req,
at->powner,
(int)at->bpowner,
at->owner,
(int)at->bowner,
(u_int)at->csum,
s);
DEBUG_PRINTF("memcheck:memory has been changed while free - here it is:\n");
for (i = 0; (u_int)i < (at->size - sizeof(struct memLinks)); i++) {
DEBUG_PRINTF("%2.2x ", at->data[i]);
if (((i + 1) % 16) == 0) {
DEBUG_PRINTF("\n");
}
}
if (i && ((i % 16) != 0)) {
DEBUG_PRINTF("\n");
}
DEBUG_PRINTF("memcheck:continuing but there is a problem!\n");
}
}
void
setMemoryOfFreed(struct memLinks *at)
{
int i;
unsigned int s;
s = 0;
for (i = 0; i < (at->size - sizeof(struct memLinks)); i++) {
s += (uint8_t)at->data[i];
}
at->csum = s;
}
void *
memcheck_malloc(size_t size, char *x, int y)
{
char *newd;
u_char *endPat;
struct memLinks **from, **addTo, *at, *prev;
int *cntUp;
void *retVal;
int i, j, ii, jj;
size_t memSize;
if (memory_inited == 0) {
initMemoryLock();
}
if (size == 8) {
ii = 0;
jj = i;
}
/* pick a queue. */
if (size <= 32) {
from = &free32;
addTo = &head32;
cntUp = &countOf32;
memSize = 32 + MEMORY_PADDING + sizeof(struct memLinks);
} else if (size <= 64) {
cntUp = &countOf64;
addTo = &head64;
from = &free64;
memSize = 64 + MEMORY_PADDING + sizeof(struct memLinks);
} else if (size <= 128) {
cntUp = &countOf128;
addTo = &head128;
from = &free128;
memSize = 128 + MEMORY_PADDING + sizeof(struct memLinks);
} else if (size <= 512) {
cntUp = &countOf512;
addTo = &head512;
from = &free512;
memSize = 512 + MEMORY_PADDING + sizeof(struct memLinks);
} else {
cntUp = &countOf1024;
from = &free1024;
addTo = &head1024;
if (size <= 1024) {
memSize = 1024 + MEMORY_PADDING + sizeof(struct memLinks);
} else {
memSize = size + MEMORY_PADDING + sizeof(struct memLinks);
}
}
retVal = NULL;
at = NULL;
if (from != NULL) {
/* See if one exists. */
prev = NULL;
for (at = *from; at != NULL; at = at->nextFree) {
if ((at->usedFree == 0) &&
(at->size - (sizeof(struct memLinks) + MEMORY_PADDING)) >= size) {
retVal = (void *)&at->data[PADDING_HALF];
if (prev == NULL) {
*from = at->nextFree;
} else {
prev->nextFree = at->nextFree;
}
break;
} else {
prev = at;
}
}
}
if (retVal == NULL) {
/* Must grow. */
int xx;
xx = *cntUp;
xx++;
*cntUp = xx;
newd = (char *)malloc(memSize + 16);
if (newd == NULL) {
return ((void *)NULL);
}
memset(newd, 0, (memSize+16));
if (((unsigned long)newd + memSize + 16) > highest) {
highest = (unsigned long)newd + memSize + 16;
}
if ((unsigned long)newd < lowest) {
lowest = (unsigned long)newd;
}
at = (struct memLinks *)((unsigned long)newd + 8);
at->markA = MARKA;
at->markB = MARKB;
at->size = memSize;
at->req = size;
at->next = *addTo;
at->nextFree = NULL;
at->powner = 0;
at->bpowner = 0;
at->owner = x;
at->bowner = y;
*addTo = at;
at->usedFree = 1;
retVal = (void *)&at->data[PADDING_HALF];
} else {
verifyMemoryOf(at);
/*
* Mark the reused here, that way the previous previous will
* point two levels if verifyMemoryOf() fails.
*/
at->req = size;
at->usedFree = 1;
at->powner = at->owner;
at->bpowner = at->bowner;
at->owner = x;
at->bowner = y;
}
/* Now prep the data portion. */
endPat = at->data;
if (((unsigned long)endPat < lowest) || ((unsigned long)endPat > highest)) {
DEBUG_PRINTF("memcheck:New error -- Internal error\n");
abort();
}
j = 250;
for (i = 0; i < PADDING_HALF; i++) {
endPat[i] = (u_char)j;
j--;
}
if (((unsigned long)endPat < lowest) || ((unsigned long)endPat > highest)) {
DEBUG_PRINTF("memcheck:New error -- Internal error2\n");
abort();
}
endPat = &at->data[(PADDING_HALF + size)];
for (i = 0; i < PADDING_HALF; i++) {
/* 1 - 20 in last 20 bytes. */
endPat[i] = (u_char)(j);
j--;
}
if (size == 8) {
ii = 0;
jj = ii;
}
/* pthread_mutex_unlock(&mu); */
return (retVal);
}
void *
memcheck_calloc(size_t num, size_t size, char *x, int y)
{
size_t z;
void *v;
z = num * size;
v = memcheck_malloc(z, x, y);
if (v) {
memset(v, 0, z);
}
return (v);
}
struct memLinks *
validMemory(struct memLinks *at)
{
struct memLinks *tt, *newat;
if ((at->markA == MARKA) &&
(at->markB == MARKB)) {
if (at->next) {
if (((u_long)at->next < lowest) ||
((u_long)at->next > highest)) {
tt = NULL;
} else {
tt = at;
}
} else {
tt = at;
}
} else {
tt = NULL;
}
if (tt == NULL) {
/* attempt to see if it has a 8 byte pad i.e. a array */
newat = (struct memLinks *)((u_long)(at) - 8);
if ((newat->markA == MARKA) &&
(newat->markB == MARKB)) {
if (newat->next) {
if (((u_long)newat->next < lowest) ||
((u_long)newat->next > highest)) {
tt = NULL;
} else {
tt = newat;
}
} else {
tt = newat;
}
} else {
tt = NULL;
}
}
if (tt == NULL) {
/* attempt to see if it has a 4 byte pad (for lynxOS) */
newat = (struct memLinks *)((u_long)(at) - 4);
if ((newat->markA == MARKA) &&
(newat->markB == MARKB)) {
if (newat->next) {
if (((u_long)newat->next < lowest) ||
((u_long)newat->next > highest)) {
tt = NULL;
} else {
tt = newat;
}
} else {
tt = newat;
}
} else {
tt = NULL;
}
}
return (tt);
}
void
memcheck_free(void *delData, char *file, int line)
{
struct memLinks *at, *tt;
u_long calc;
u_char *endPat;
size_t size;
int i, j;
if (memory_inited == 0) {
initMemoryLock();
}
if (delData == NULL) {
DEBUG_PRINTF("memcheck:Attempt to free NULL pointer %s:%d\n",
file, line
);
abort();
}
if (((unsigned long)delData < lowest) || ((unsigned long)delData > highest)) {
DEBUG_PRINTF("memcheck:Bounds error - trying to free memory outside valid bounds %s:%d\n", file, line);
abort();
}
calc = (unsigned long)delData;
calc -= PADDING_HALF;
calc -= (sizeof(struct memLinks) - sizeof(at->data));
at = (struct memLinks *)calc;
tt = validMemory(at);
if (tt == NULL) {
DEBUG_PRINTF("memcheck:Attempt to free memory not alocated from my queue %s:%d\n", file, line);
abort();
}
at = tt;
size = at->req;
if (at->usedFree == 1) {
at->usedFree = 0;
} else {
DEBUG_PRINTF("memcheck:Attempt to free memory already free %s:%d\n", file, line);
abort();
}
endPat = at->data;
j = 250;
for (i = 0; i < PADDING_HALF; i++) {
if (endPat[i] != (u_char)j) {
DEBUG_PRINTF("memcheck:Overwrote memory at beg of block at %d 0x%x vs 0x%x %s:%d\n",
i, (u_char)endPat[i], (u_char)j, file, line);
DEBUG_PRINTF("memcheck:Owner:%s:%d Previous Owner %s:%d size:%d req:%d\n",
at->owner, (int)at->bowner,
at->powner, (int)at->bpowner,
(int)at->size, (int)at->req);
abort();
}
j--;
}
endPat = &at->data[(PADDING_HALF + size)];
for (i = 0; i < PADDING_HALF; i++) {
if (endPat[i] != (u_char)(j)) {
DEBUG_PRINTF("memchek:Overwrote memory at end of allocated block at %d 0x%x vs 0x%x %s:%d\n",
i, (u_char)endPat[i], (u_char)j, file, line);
DEBUG_PRINTF("memcheck:Owner:%s:%d Previous Owner %s:%d size:%d req:%d\n",
at->owner, (int)at->bowner,
at->powner, (int)at->bpowner,
(int)at->size, (int)at->req);
abort();
}
j--;
}
setMemoryOfFreed(at);
if (size <= 32) {
tt->nextFree = free32;
free32 = tt;
} else if (size <= 64) {
tt->nextFree = free64;
free64 = tt;
} else if (size <= 128) {
tt->nextFree = free128;
free128 = tt;
} else if (size <= 512) {
tt->nextFree = free512;
free512 = tt;
} else {
tt->nextFree = free1024;
free1024 = tt;
}
}
void
printStats(struct memLinks *who, int printAll, char *queueName)
{
int cnt, bcnt;
struct memLinks *at;
int i, j;
u_char *endPat;
at = who;
bcnt = cnt = 0;
while (at != NULL) {
if (at->usedFree != 0) {
bcnt++;
}
cnt++;
at = at->next;
}
if ((printAll) && bcnt) {
at = who;
DEBUG_PRINTF("memcheck:%s\n", queueName);
while (at != NULL) {
if ((at->usedFree != 0) && (at->owner != NULL)) {
DEBUG_PRINTF("memcheck:Piece 0x%p size:%d used:%d left un-freed owner:%s:%d\n",
&at->data[PADDING_HALF],
(int)at->size,
(int)at->req,
at->owner,
(int)at->bowner);
if (printAll > 1) {
for (i = 0; (u_int)i < at->req; i++) {
DEBUG_PRINTF("%2.2x ", at->data[(PADDING_HALF + i)]);
if (((i + 1) % 16) == 0) {
DEBUG_PRINTF("\n");
}
}
if (i && ((i % 16) != 0)) {
DEBUG_PRINTF("\n");
}
}
endPat = at->data;
j = 250;
for (i = 0; i < PADDING_HALF; i++) {
if (endPat[i] != (u_char)j) {
DEBUG_PRINTF("memcheck:Overwritten memory at beg of allocated block at %p\n",
at);
}
j--;
}
endPat = &at->data[(PADDING_HALF + at->req)];
for (i = 0; i < PADDING_HALF; i++) {
if (endPat[i] != (u_char)(j)) {
DEBUG_PRINTF("memcheck:Overwrtiten memory at end of allocated block at %p\n",
at);
}
j--;
}
}
at = at->next;
}
} else if (printAll == 0) {
DEBUG_PRINTF("memcheck:%s\n", queueName);
DEBUG_PRINTF("memcheck:Totals:%d on Queue %d Aloc'd\n", cnt, bcnt);
}
}
void
printMemStatus(int printAll)
{
printStats(head32, printAll, "32 Byte Queue");
printStats(head64, printAll, "64 Byte Queue");
printStats(head128, printAll, "128 Byte Queue");
printStats(head512, printAll, "512 Byte Queue");
printStats(head1024, printAll, "1024 Byte Queue");
}
void
memInfo(int queue, int num)
{
struct memLinks *theOne, *at;
int i;
if (queue == 32) {
theOne = head32;
} else if (queue == 64) {
theOne = head64;
} else if (queue == 128) {
theOne = head128;
} else if (queue == 512) {
theOne = head512;
} else if (queue == 1024) {
theOne = head1024;
} else {
DEBUG_PRINTF("memcheck:Unknown queue %d 32/64/128/512/1024\n", queue);
return;
}
for (i = 0, at = theOne; at != NULL; at = at->next, i++) {
if (num == i) {
DEBUG_PRINTF("memcheck:Found the %dth entry:\n", num);
DEBUG_PRINTF("memcheck:0x%p size:%d used:%d left un-freed owner:%s:%d (%s:%d)\n",
&at->data[PADDING_HALF],
(int)at->size,
(int)at->req,
at->owner, at->bowner,
at->powner, at->bpowner);
for (i = 0; (u_int)i < at->req; i++) {
DEBUG_PRINTF("%2.2x ", at->data[(PADDING_HALF + i)]);
if (((i + 1) % 16) == 0) {
DEBUG_PRINTF("\n");
}
}
if (i && ((i % 16) != 0)) {
DEBUG_PRINTF("\n");
}
break;
}
}
}
void
markMemory(void *mem, char *mark, int line)
{
struct memLinks *at, *tt;
u_long calc;
if (mem == NULL)
return;
if (((unsigned long)mem < lowest) || ((unsigned long)mem > highest)) {
DEBUG_PRINTF("Bounds error - trying to mark memory outside valid bounds\n");
abort();
}
calc = (unsigned long)mem;
calc -= PADDING_HALF;
calc -= (sizeof(struct memLinks) - sizeof(at->data));
at = (struct memLinks *)calc;
tt = validMemory(at);
if (tt == NULL) {
DEBUG_PRINTF("Attempt to free memory not alocated from my queue \n");
abort();
}
at = tt;
if (tt == NULL) {
DEBUG_PRINTF("Attempt to mark memory not alocated from my queue \n");
abort();
}
at->owner = mark;
at->bowner = line;
}