/*
 * ----------------------------------------------------------------
 * Night Light Memory Allocation Library Functions (memcalls.c)
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2007 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 * Last modified by:
 * Jonas Kvinge (04.10.2006)
 *
 */

#define MEMCALLS_C
#define LIBRARY

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 0			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 0		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 0		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 0		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 0		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 0			/* Signal functions */
#define NEED_SYS_SOCKET_H 0		/* Socket functions */
#define NEED_NETDB_H 0			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */

#include "config.h"
#include "headers.h"
#include "defines.h"
#include "memcalls_int.h"

#ifdef MALLOC_REDEFINE
  #error "Sanity check: malloc() can't be redefined in here!"
#endif

/* VARIABLES - JONAS (21.09.2001) */

struct MemTable_Struct *MemTable_Head = NULL;
struct MemTable_Struct *MemTable_Tail = NULL;
unsigned long int G_Allocations = 0;
struct MemTable_Struct *MemHashTable[MALLOC_HASH_SIZE] = { NULL };
size_t MemPrefixSize = (const size_t) sizeof(MALLOC_PREFIX);
size_t MemPostfixSize = (const size_t) sizeof(MALLOC_POSTFIX);
unsigned short int IgnoreWildPTR = FALSE;

/* MEMTABLE_ADD - JONAS (21.09.2001) */

void memtable_add(const void *const PTR, const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const size_t Size) {

  struct MemTable_Struct *MemTableS = NULL;
  struct MemTable_Struct *MemTableS_NEW = NULL;
  unsigned long int Hash = 0;

  assert(PTR != NULL);
  assert(FilePT != NULL);
  assert(FunctionPT != NULL);

  MemTableS_NEW = malloc(sizeof(struct MemTable_Struct));
  if (MemTableS_NEW == NULL) {
    return;
  }
  memset(MemTableS_NEW, 0, sizeof(struct MemTable_Struct));

  MemTableS_NEW->PTR = (const void *const) PTR;
  MemTableS_NEW->File = (const char *const) FilePT;
  MemTableS_NEW->Line = (const unsigned short int) Line;
  MemTableS_NEW->Function = (const char *const) FunctionPT;
  MemTableS_NEW->Size = Size;
  MemTableS_NEW->Time = NOW;

  if (MemTable_Head == NULL) {
    MemTable_Head = MemTableS_NEW;
    MemTable_Tail = MemTableS_NEW;
  }
  else {
    MemTableS = MemTable_Tail;
    MemTableS->Next = MemTableS_NEW;
    MemTableS_NEW->Prev = MemTableS;
    MemTable_Tail = MemTableS_NEW;
  }

  Hash = MallocHash(PTR);

  if (MemHashTable[Hash] == NULL) { MemHashTable[Hash] = MemTableS_NEW; }
  else {
    for (MemTableS = MemHashTable[Hash] ; (MemTableS->NextH != NULL) ; MemTableS = MemTableS->NextH);
    MemTableS->NextH = MemTableS_NEW;
    MemTableS_NEW->PrevH = MemTableS;
  }

  G_Allocations++;

#ifdef DEBUGPRINT
  DEBUGPRINT(BITMASK_DEBUG_MEMORY, "%s() - Pointer: %p - File: %s - Line: %d - Function: %s", __FUNCTION__, PTR, FilePT, Line, FunctionPT);
#endif

}

/* MEMTABLE_REM - JONAS (21.09.2001) */

void memtable_rem(struct MemTable_Struct *MemTableS) {

  struct MemTable_Struct *MemTableH = NULL;
  unsigned long int Hash = 0;

  assert(MemTableS != NULL);

  if (MemTableS->Prev == NULL) { MemTable_Head = MemTableS->Next; }
  else { MemTableS->Prev->Next = MemTableS->Next; }

  if (MemTableS->Next == NULL) { MemTable_Tail = MemTableS->Prev; }
  else { MemTableS->Next->Prev = MemTableS->Prev; }

  Hash = MallocHash(MemTableS->PTR);
  for (MemTableH = MemHashTable[Hash] ; ((MemTableH != NULL) && (MemTableH != MemTableS)) ; MemTableH = MemTableH->NextH);
  assert(MemTableH == MemTableS);

  if (MemTableH->PrevH != NULL) { MemTableH->PrevH->NextH = MemTableH->NextH; }
  if (MemTableH->NextH != NULL) { MemTableH->NextH->PrevH = MemTableH->PrevH; }

  if (MemHashTable[Hash] == MemTableH) { MemHashTable[Hash] = MemTableH->NextH; }

  G_Allocations--;

#ifdef DEBUGPRINT
  DEBUGPRINT(BITMASK_DEBUG_MEMORY, "%s() - Pointer: %p - File: %s - Line: %d - Function: %s", __FUNCTION__, MemTableS->PTR, MemTableS->File, MemTableS->Line, MemTableS->Function);
#endif

  free(MemTableS);

}

/* MEMTABLE_GET - JONAS (21.09.2001) */

struct MemTable_Struct *memtable_get(const void *const PTR) {

  struct MemTable_Struct *MemTableH = MemHashTable[MallocHash(PTR)];

  while ((MemTableH != NULL) && (PTR != MemTableH->PTR)) { MemTableH = MemTableH->NextH; }

  return(MemTableH);

}

/* MEMALLOC - JONAS (21.09.2001) */

void *memalloc(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const size_t MemSize) {

  void *MemPTR = NULL;
  void *PrefixPTR = NULL;
  void *PostfixPTR = NULL;
  size_t RealSize = MemSize + MemPrefixSize + MemPostfixSize;

#ifdef DEBUGPRINT
  DEBUGPRINT(BITMASK_DEBUG_MEMORY, "%s() - File: %s - Line: %d - Function: %s - Size: %ld", __FUNCTION__, FilePT, Line, FunctionPT, (PRINT_SIZE_T) MemSize);
#endif

  if (MemSize > MALLOC_LIMIT) {
    fprintf(stderr, "ERROR: Memory request to large from function %s() (%s:%d) (%ld bytes).\n", FunctionPT, FilePT, Line, (PRINT_SIZE_T) MemSize);
    return(NULL);
  }

  PrefixPTR = malloc(RealSize);
  if (PrefixPTR == NULL) {
    fprintf(stderr, "ERROR: Memory allocation failure in function %s() (%s:%d): %ld bytes: [%d] %s\n", FunctionPT, FilePT, Line, (PRINT_SIZE_T) MemSize, errno, strerror(errno));
    return(NULL);
  }
  memset(PrefixPTR, 0, RealSize);

  PostfixPTR = PrefixPTR + MemPrefixSize + MemSize;
  MemPTR = PrefixPTR + MemPrefixSize;

  strcpy(PrefixPTR, MALLOC_PREFIX);
  strcpy(PostfixPTR, MALLOC_POSTFIX);

  memtable_add(MemPTR, FilePT, Line, FunctionPT, MemSize);

  return(MemPTR);

}

/* MEMREALLOC - JONAS (26.03.2002) */

void *memrealloc(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, void *const OldPTR, const size_t MemSize) {

  struct MemTable_Struct *MemTableS = NULL;
  void *NewPTR = NULL;

  void *OldPrefixPTR = NULL;
  void *OldPostfixPTR = NULL;

  void *NewPrefixPTR = NULL;
  void *NewPostfixPTR = NULL;

  size_t RealSize = 0;

#ifdef DEBUGPRINT
  DEBUGPRINT(BITMASK_DEBUG_MEMORY, "%s() - File: %s - Line: %d - Function: %s - Size: %ld", __FUNCTION__, FilePT, Line, FunctionPT, (PRINT_SIZE_T) MemSize);
#endif

  if (OldPTR != NULL) {

    MemTableS = memtable_get(OldPTR);
    if (MemTableS == NULL) {
      if (IgnoreWildPTR == FALSE) { fprintf(stderr, "ERROR: Wild pointer %p from function %s() (%s:%d) passed to function realloc().\n", OldPTR, FunctionPT, FilePT, Line); }
    }
    else {

      if (MemTableS->Size == MemSize) { return(OldPTR); }

      OldPrefixPTR = OldPTR - MemPrefixSize;
      OldPostfixPTR = OldPTR + MemTableS->Size;

      if (strncmp(OldPrefixPTR, MALLOC_PREFIX, MALLOC_PREFIX_LEN) != 0) {
        fprintf(stderr, "ERROR: Magic memory prefix \"%s\" corrupt on pointer %p from function %s() (%s:%d) passed to function realloc().\n", MALLOC_PREFIX, OldPTR, FunctionPT, FilePT, Line);
        abort();
      }
      if (strncmp(OldPostfixPTR, MALLOC_POSTFIX, MALLOC_POSTFIX_LEN) != 0) {
        fprintf(stderr, "ERROR: Magic memory postfix \"%s\" corrupt on pointer %p from function %s() (%s:%d) passed to function realloc().\n", MALLOC_POSTFIX, OldPTR, FunctionPT, FilePT, Line);
        abort();
      }
      memtable_rem(MemTableS);
    }
  }

  if (MemSize > MALLOC_LIMIT) {
    fprintf(stderr, "ERROR: Memory request to large from function %s (%s:%d) (%ld bytes).\n", FunctionPT, FilePT, Line, (PRINT_SIZE_T) MemSize);
    return(NULL);
  }

  if (MemSize == 0) {
    if (OldPrefixPTR != NULL) { free(OldPrefixPTR); }
    return(NULL);
  }

  if (OldPostfixPTR != NULL) { memset(OldPostfixPTR, 0, MemPostfixSize); }

  RealSize += MemPrefixSize;
  RealSize += MemSize;
  RealSize += MemPostfixSize;

  NewPrefixPTR = realloc(OldPrefixPTR, RealSize);
  if (NewPrefixPTR == NULL) {
    if (RealSize > 0) { fprintf(stderr, "ERROR: Memory allocation failure in function %s (%s:%d): %ld bytes: [%d] %s\n", FunctionPT, FilePT, Line, (PRINT_SIZE_T) MemSize, errno, strerror(errno)); }
    return(NULL);
  }

  NewPostfixPTR = NewPrefixPTR + MemPrefixSize + MemSize;
  NewPTR = NewPrefixPTR + MemPrefixSize;

  strcpy(NewPrefixPTR, MALLOC_PREFIX);
  strcpy(NewPostfixPTR, MALLOC_POSTFIX);

  memtable_add(NewPTR, FilePT, Line, FunctionPT, MemSize);

  return(NewPTR);

}

/* MEMCALLOC - JONAS (21.09.2001) */

void *memcalloc(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, const size_t Elements, const size_t Size) {

  size_t MemSize = (Size * Elements);
  void *PTR = memalloc(FilePT, Line, FunctionPT, MemSize);

  return(PTR);

}

/* MEMFREE - JONAS (21.09.2001) */

signed short int memfree(const char *const FilePT, const unsigned short int Line, const char *const FunctionPT, void *const MemPTR) {

  struct MemTable_Struct *MemTableS = NULL;
  void *PrefixPTR = NULL;
  void *PostfixPTR = NULL;
  size_t TotalSize = 0;

#ifdef DEBUGPRINT
  DEBUGPRINT(BITMASK_DEBUG_MEMORY, "%s() - File: %s - Line: %d - Function: %s - Pointer: %p", __FUNCTION__, FilePT, Line, FunctionPT, MemPTR);
#endif

  if (MemPTR == NULL) { return(SUCCESS); }

  MemTableS = memtable_get(MemPTR);
  if (MemTableS == NULL) {
    if (IgnoreWildPTR == FALSE) { fprintf(stderr, "ERROR: Wild pointer %p from function %s (%s:%d) passed to function free().\n", MemPTR, FunctionPT, FilePT, Line); }
    return(ERROR);
  }

  PrefixPTR = MemPTR - MemPrefixSize;
  PostfixPTR = MemPTR + MemTableS->Size;
  TotalSize = MemPrefixSize + MemTableS->Size + MemPostfixSize;

  if (strncmp(PrefixPTR, MALLOC_PREFIX, MALLOC_PREFIX_LEN) != 0) {
    fprintf(stderr, "ERROR: Magic memory prefix \"%s\" corrupt on pointer %p from function %s (%s:%d) passed to function free().\n", MALLOC_PREFIX, MemPTR, FunctionPT, FilePT, Line);
    abort();
  }

  if (strncmp(PostfixPTR, MALLOC_POSTFIX, MALLOC_POSTFIX_LEN) != 0) {
    fprintf(stderr, "ERROR: Magic memory postfix \"%s\" corrupt on pointer %p from function %s (%s:%d) passed to function free().\n", MALLOC_POSTFIX, MemPTR, FunctionPT, FilePT, Line);
    abort();
  }

  memtable_rem(MemTableS);

  memset(PrefixPTR, MALLOC_REDBYTE, TotalSize);
  free(PrefixPTR);

  return(SUCCESS);

}


syntax highlighted by Code2HTML, v. 0.9.1