summaryrefslogblamecommitdiffstats
path: root/cpukit/libcsupport/src/malloc_boundary.c
blob: 706e2242947676ea09e8033b2ec9c8e28223b780 (plain) (tree)

































































































































































































                                                                                   
/*
 *  RTEMS Malloc Block Boundary Integrity Checker
 *
 *  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!
 *  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!
 *
 *  This file is built but never called.  It is a first
 *  step in reintegrating this functionality.
 *  This code was disabled for a LONG time in malloc.c.
 *  This is a restructured and slightly modified version
 *  that should be able to be configured as a plugin BUT
 *  it has not been tested recently.  When it has been
 *  tested again, please remove this comment.
 *
 *  JOEL: I have not analyzed this code in terms of
 *        the heap changes post 4.6.  It is possible
 *        that that way the boundary area is carved
 *        off breaks the alignment.
 *
 *  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!
 *  WARNING!!!  WARNING!!!  WARNING!!!  WARNING!!!
 *
 *  COPYRIGHT (c) 1989-2007.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include "malloc_p.h"

#include <stdio.h>

#ifdef RTEMS_NEWLIB

#define SENTINELSIZE    12
#define SENTINEL       "\xD1\xAC\xB2\xF1" "BITE ME"
#define CALLCHAINSIZE 5

struct mallocNode {
  struct mallocNode *back;
  struct mallocNode *forw;
  int                callChain[CALLCHAINSIZE];
  size_t             size;
  void              *memory;
};

struct mallocNode mallocNodeHead;

void rtems_malloc_boundary_initialize(void)
{
  mallocNodeHead.back = &mallocNodeHead;
  mallocNodeHead.forw = &mallocNodeHead;
}

uint32_t rtems_malloc_boundary_overhead(void)
{
  return sizeof(struct mallocNode) + SENTINELSIZE;
}

void rtems_malloc_boundary_at_malloc(
  void     *pointer,
  size_t    size
)
{
  void *return_this;
  struct mallocNode *mp = (struct mallocNode *)pointer;
  int *fp, *nfp, i;

  _RTEMS_Lock_allocator();
    mp->memory = mp + 1;
    return_this = mp->memory;
    mp->size = size - (sizeof(struct mallocNode) + SENTINELSIZE);
    fp = (int *)&size - 2;
    for (i = 0 ; i < CALLCHAINSIZE ; i++) {
      mp->callChain[i] = fp[1];
      nfp = (int *)(fp[0]);
      if((nfp <= fp) || (nfp > (int *)(1 << 24)))
       break;
      fp = nfp;
    }
    while (i < CALLCHAINSIZE)
      mp->callChain[i++] = 0;
    memcpy((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE);
    mp->forw = mallocNodeHead.forw;
    mp->back = &mallocNodeHead;
    mallocNodeHead.forw->back = mp;
    mallocNodeHead.forw = mp;
  _RTEMS_Unlock_allocator();
}

void reportMallocError(const char *msg, struct mallocNode *mp);

void rtems_malloc_boundary_at_free(
  void     *pointer
)
{
  struct mallocNode *mp = (struct mallocNode *)pointer - 1;
  struct mallocNode *mp1;

  _RTEMS_Lock_allocator();
    if ((mp->memory != (mp + 1)) ||
        (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0))
      reportMallocError("Freeing with inconsistent pointer/sentinel", mp);
    mp1 = mallocNodeHead.forw;
    while (mp1 != &mallocNodeHead) {
      if (mp1 == mp)
        break;
      mp1 = mp1->forw;
    }
    if (mp1 != mp)
      reportMallocError("Freeing, but not on allocated list", mp);
    mp->forw->back = mp->back;
    mp->back->forw = mp->forw;
    mp->back = mp->forw = NULL;
    pointer = mp;
  _RTEMS_Unlock_allocator();
}

void rtems_malloc_boundary_at_realloc(
  void     *pointer,
  size_t    size
)
{
  /* this needs to be implemented */
}

/*
 *  Malloc boundary support plugin
 */
rtems_malloc_boundary_functions_t rtems_malloc_boundary_functions_table = {
  rtems_malloc_boundary_initialize,
  rtems_malloc_boundary_overhead,
  rtems_malloc_boundary_at_malloc,
  rtems_malloc_boundary_at_free,
  rtems_malloc_boundary_at_realloc,
};

rtems_malloc_boundary_functions_t *rtems_malloc_boundary_helpers = NULL;
/*   &rtems_malloc_boundary_functions_table; */

void reportMallocError(const char *msg, struct mallocNode *mp)
{
    unsigned char *sp = (unsigned char *)mp->memory + mp->size;
    int i, ind = 0;
    static char cbuf[500];
    ind += sprintf(cbuf+ind, "Malloc Error: %s\n", msg);
    if ((mp->forw->back != mp) || (mp->back->forw != mp))
        ind += sprintf(cbuf+ind,
            "mp:%p  mp->forw:%p  mp->forw->back:%p  "
            "mp->back:%p  mp->back->forw:%p\n",
            mp, mp->forw, mp->forw->back, mp->back, mp->back->forw);
    if (mp->memory != (mp + 1))
        ind += sprintf(cbuf+ind, "mp+1:%p  ", mp + 1);
    ind += sprintf(cbuf+ind, "mp->memory:%p  mp->size:%d\n", mp->memory, mp->size);
    if (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0) {
        ind += sprintf(cbuf+ind, "mp->sentinel: ");
        for (i = 0 ; i < SENTINELSIZE ; i++)
            ind += sprintf(cbuf+ind, " 0x%x", sp[i]);
        ind += sprintf(cbuf+ind, "\n");
    }
    ind += sprintf(cbuf+ind, "Call chain:");
    for (i = 0 ; i < CALLCHAINSIZE ; i++) {
        if (mp->callChain[i] == 0)
            break;
        ind += sprintf(cbuf+ind, " 0x%x", mp->callChain[i]);
    }
    printk("\n\n%s\n\n", cbuf);
}

void checkMallocArena(void)
{
  struct mallocNode *mp;

  _RTEMS_Lock_allocator();
    for ( mp = mallocNodeHead.forw; mp != &mallocNodeHead ; mp = mp->forw ) {
      if ((mp->forw->back != mp) || (mp->back->forw != mp))
        reportMallocError("Pointers mangled", mp);
      if ((mp->memory != (mp + 1)) ||
          (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0))
        reportMallocError("Inconsistent pointer/sentinel", mp);
    }
  _RTEMS_Unlock_allocator();
}

#endif