johnsonjh/duma

View on GitHub
duma_hlp.h

Summary

Maintainability
Test Coverage
/*
 * DUMA - Red-Zone memory allocator.
 * Copyright (C) 2002-2009 Hayati Ayguen <h_ayguen@web.de>, Procitec GmbH
 * License: GNU LGPL (GNU Lesser General Public License, see COPYING-GPL)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * FILE CONTENTS:
 * internal implementation file
 * contains helper functions for DUMA
 */

/* Function: reduceProtectedMemory
 *
 * delete reductionSizekB amount of memory, which has already
 * been freed but got protected
 * return != 0 when more memory reducable
 */
static int reduceProtectedMemory(size_t reductionSizekB) {
  struct _DUMA_Slot *slot = _duma_g.allocList;
  size_t count = _duma_s.slotCount;
  size_t alreadyReducekB = 0;

#ifndef WIN32
  /* Windows VirtualFree(,,MEM_RELEASE) can only free whole allocations. not
   * parts */

  size_t delSize, newSize;

  /* 1- try reducing memory to just keep page(s) with userAddress */
  for (; count > 0 && alreadyReducekB < reductionSizekB; --count, ++slot)
    if (DUMAST_ALL_PROTECTED == slot->state) {
      /* free memory above userAddr; keep userAddr protected */
      newSize = (char *)slot->userAddress - (char *)slot->internalAddress;
      newSize = (newSize + DUMA_PAGE_SIZE) & ~(DUMA_PAGE_SIZE - 1);
      delSize = slot->internalSize - newSize;
      Page_Delete((char *)slot->internalAddress + newSize, delSize);
      alreadyReducekB += (delSize + 1023) >> 10;
      slot->state = DUMAST_BEGIN_PROTECTED;
      /* but keep the slot and userAddr */
      slot->internalSize = newSize;

      if (alreadyReducekB >= reductionSizekB) {
        _duma_s.sumProtectedMem -= alreadyReducekB;
        _duma_s.sumAllocatedMem -= alreadyReducekB;
        return 1;
      }
    }
#endif
  /* 2- deallocate all page(s) with userAddress, empty whole slot */
  slot = _duma_g.allocList;
  count = _duma_s.slotCount;
  for (; count > 0 && alreadyReducekB < reductionSizekB; --count, ++slot)
    if (DUMAST_BEGIN_PROTECTED == slot->state
#if defined(WIN32)
        || DUMAST_ALL_PROTECTED == slot->state
#endif
    ) {
      /* free all the memory */
      Page_Delete(slot->internalAddress, slot->internalSize);
      alreadyReducekB += (slot->internalSize + 1023) >> 10;
      /* free slot and userAddr */
      slot->internalAddress = slot->userAddress = 0;
      slot->internalSize = slot->userSize = 0;
      slot->state = DUMAST_EMPTY;
      slot->allocator = EFA_INT_ALLOC;
#ifndef DUMA_NO_LEAKDETECTION
      slot->fileSource = DUMAFS_EMPTY;
      slot->filename = 0;
      slot->lineno = 0;
#endif

      if (alreadyReducekB >= reductionSizekB) {
        _duma_s.sumProtectedMem -= alreadyReducekB;
        _duma_s.sumAllocatedMem -= alreadyReducekB;
        return 1;
      }
    }

  return 0;
}

/* Function: slotForUserAddress
 *
 * Find the slot structure for a user address.
 */
static struct _DUMA_Slot *slotForUserAddress(void *address) {
  struct _DUMA_Slot *slot = _duma_g.allocList;
  size_t count = _duma_s.slotCount;

  for (; count > 0; --count, ++slot)
    if (slot->userAddress == address)
      return slot;
  return 0;
}

/* Function: nearestSlotForUserAddress
 *
 * Find the nearest slot structure for a user address.
 */
static struct _DUMA_Slot *nearestSlotForUserAddress(void *userAddress) {
  struct _DUMA_Slot *slot = _duma_g.allocList;
  size_t count = _duma_s.slotCount;

  for (; count > 0; --count, ++slot)
    if ((char *)slot->internalAddress <= (char *)userAddress &&
        (char *)userAddress <=
            (char *)slot->internalAddress + slot->internalSize)
      return slot;
  return 0;
}

/* Function: _duma_init_slack
 *
 * Initialise the no mans land, for a given slot
 */
static void _duma_init_slack(struct _DUMA_Slot *slot) {
  char *accBegAddr, *accEndAddr;
  char *tmpBegAddr, *tmpEndAddr;

#ifdef DUMA_EXPLICIT_INIT
  slot->slackfill = _duma_s.SLACKFILL;
#endif

  /* nothing to do for zero userSize */
  if (!slot->userSize)
    return;

  /* calculate accessible non-protectable address area */
  if ((char *)slot->protAddress < (char *)slot->userAddress) {
    /* DUMA_PROTECT_BELOW was 1 when allocating this piece of memory */
    accBegAddr = (char *)slot->userAddress;
    accEndAddr = (char *)slot->internalAddress + slot->internalSize;
  } else {
    /* DUMA_PROTECT_BELOW was 0 when allocating this piece of memory */
    accBegAddr = (char *)slot->internalAddress;
    accEndAddr = (char *)slot->protAddress;
  }

  tmpBegAddr = accBegAddr;
  tmpEndAddr = (char *)slot->userAddress;
  while (tmpBegAddr < tmpEndAddr)
    *tmpBegAddr++ = (char)_duma_s.SLACKFILL;

  tmpBegAddr = (char *)slot->userAddress + slot->userSize;
  tmpEndAddr = accEndAddr;
  while (tmpBegAddr < tmpEndAddr)
    *tmpBegAddr++ = (char)_duma_s.SLACKFILL;
}

/* Function: _duma_check_slack
 *
 * Checks the integrity of no mans land, for a given slot
 */
static void _duma_check_slack(struct _DUMA_Slot *slot) {
  char *accBegAddr, *accEndAddr;
  char *tmpBegAddr, *tmpEndAddr;
  char slackfill;
#ifdef DUMA_EXPLICIT_INIT
  slackfill = (char)slot->slackfill;
#else
  slackfill = (char)_duma_s.SLACKFILL;
#endif

  /* nothing to do for zero userSize */
  if (!slot->userSize)
    return;

  if (!slot->internalAddress)
    return;

  /* calculate accessible non-protectable address area */
  if ((char *)slot->protAddress < (char *)slot->userAddress) {
    /* DUMA_PROTECT_BELOW was 1 when allocating this piece of memory */
    accBegAddr = (char *)slot->userAddress;
    accEndAddr = (char *)slot->internalAddress + slot->internalSize;
  } else {
    /* DUMA_PROTECT_BELOW was 0 when allocating this piece of memory */
    accBegAddr = (char *)slot->internalAddress;
    accEndAddr = (char *)slot->protAddress;
  }

  tmpBegAddr = accBegAddr;
  tmpEndAddr = (char *)slot->userAddress;
  while (tmpBegAddr < tmpEndAddr) {
    if ((char)slackfill != *tmpBegAddr++) {
#ifndef DUMA_NO_LEAKDETECTION
      DUMA_Abort("ptr=%a: detected overwrite of ptrs no mans land below "
                 "userSpace, size=%d alloced from %s(%i)",
                 (DUMA_ADDR)slot->userAddress, (DUMA_SIZE)slot->userSize,
                 slot->filename, slot->lineno);
#else
      DUMA_Abort(
          "ptr=%a: detected overwrite of ptrs no mans land below userSpace",
          (DUMA_ADDR)slot->userAddress);
#endif
    }
  }

  tmpBegAddr = (char *)slot->userAddress + slot->userSize;
  tmpEndAddr = accEndAddr;
  while (tmpBegAddr < tmpEndAddr) {
    if ((char)slackfill != *tmpBegAddr++) {
#ifndef DUMA_NO_LEAKDETECTION
      DUMA_Abort("detected overwrite of no mans land above userSpace: ptr=%a, "
                 "size=%d\nalloced from %s(%i)",
                 (DUMA_ADDR)slot->userAddress, (DUMA_SIZE)slot->userSize,
                 slot->filename, slot->lineno);
#else
      DUMA_Abort("detected overwrite of no mans land above userSpace: ptr=%a",
                 (DUMA_ADDR)slot->userAddress);
#endif
    }
  }
}

/* Function: _duma_check_all_slacks
 *
 * Checks the integrity of all no mans land
 */
static void _duma_check_all_slacks(void) {
  struct _DUMA_Slot *slot = _duma_g.allocList;
  size_t count = _duma_s.slotCount;

  for (; count > 0; --count, ++slot) {
    /* CHECK INTEGRITY OF NO MANS LAND */
    if (DUMAST_IN_USE == slot->state && slot->userSize)
      _duma_check_slack(slot);
  }
}