source: rtems/cpukit/libcsupport/src/malloc.c @ 55d7626

4.104.114.84.95
Last change on this file since 55d7626 was 55d7626, checked in by Joel Sherrill <joel.sherrill@…>, on 07/11/07 at 20:56:10

2007-07-11 Joel Sherrill <joel.sherrill@…>

  • libcsupport/src/malloc.c: Clean up Malloc debug code.
  • score/include/rtems/score/heap.h: Spacing.
  • score/inline/rtems/score/thread.inl:
  • score/src/heapfree.c. Clean up and add explicit check of the address being freed actually being in the heap.
  • score/src/heapwalk.c: Switch to printk and do not call abort.
  • Property mode set to 100644
File size: 14.0 KB
RevLine 
[ac7d5ef0]1/*
2 *  RTEMS Malloc Family Implementation
3 *
4 *
[08311cc3]5 *  COPYRIGHT (c) 1989-1999.
[ac7d5ef0]6 *  On-Line Applications Research Corporation (OAR).
7 *
[98e4ebf5]8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
[0eae36c7]10 *  http://www.rtems.com/license/LICENSE.
[ac7d5ef0]11 *
12 *  $Id$
13 */
14
[9c49db4]15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
[1f2d5df]19#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
[ac7d5ef0]20#include <rtems.h>
[3ba74c73]21#include <rtems/libcsupport.h>
[e746a88]22#include <rtems/score/protectedheap.h>
[ac7d5ef0]23#ifdef RTEMS_NEWLIB
24#include <sys/reent.h>
25#endif
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <assert.h>
31#include <errno.h>
32#include <string.h>
[c7ca28cf]33
[1f94ed6b]34#include <unistd.h>    /* sbrk(2) */
[2751cbe0]35#include <inttypes.h>
[ac7d5ef0]36
[ebbe119e]37#include <rtems/chain.h>
[aab4664d]38
[2751cbe0]39#ifndef HAVE_UINTMAX_T
40/* Fall back to unsigned long if uintmax_t is not available */
41#define unsigned long uintmax_t
42
43#ifndef PRIuMAX
[7d6701d]44#define PRIuMAX         "lu"
[2751cbe0]45#endif
46#endif
47
[be31de7]48#ifdef MALLOC_ARENA_CHECK
49#define SENTINELSIZE    12
50#define SENTINEL       "\xD1\xAC\xB2\xF1" "BITE ME"
51#define CALLCHAINSIZE 5
52struct mallocNode {
53    struct mallocNode *back;
54    struct mallocNode *forw;
55    int                callChain[CALLCHAINSIZE];
56    size_t             size;
57    void              *memory;
58};
59static struct mallocNode mallocNodeHead = { &mallocNodeHead, &mallocNodeHead };
60void reportMallocError(const char *msg, struct mallocNode *mp)
61{
62    unsigned char *sp = (unsigned char *)mp->memory + mp->size;
63    int i, ind = 0;
64    static char cbuf[500];
65    ind += sprintf(cbuf+ind, "Malloc Error: %s\n", msg);
66    if ((mp->forw->back != mp) || (mp->back->forw != mp))
67        ind += sprintf(cbuf+ind, "mp:0x%x  mp->forw:0x%x  mp->forw->back:0x%x  mp->back:0x%x  mp->back->forw:0x%x\n",
68                        mp, mp->forw, mp->forw->back, mp->back, mp->back->forw);
69    if (mp->memory != (mp + 1))
70        ind += sprintf(cbuf+ind, "mp+1:0x%x  ", mp + 1);
71    ind += sprintf(cbuf+ind, "mp->memory:0x%x  mp->size:%d\n", mp->memory, mp->size);
72    if (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0) {
73        ind += sprintf(cbuf+ind, "mp->sentinel: ");
74        for (i = 0 ; i < SENTINELSIZE ; i++)
75            ind += sprintf(cbuf+ind, " 0x%x", sp[i]);
76        ind += sprintf(cbuf+ind, "\n");
77    }
78    ind += sprintf(cbuf+ind, "Call chain:");
79    for (i = 0 ; i < CALLCHAINSIZE ; i++) {
80        if (mp->callChain[i] == 0)
81            break;
82        ind += sprintf(cbuf+ind, " 0x%x", mp->callChain[i]);
83    }
84    printk("\n\n%s\n\n", cbuf);
85}
86#endif
87
[e746a88]88Heap_Control  RTEMS_Malloc_Heap;
[aab4664d]89Chain_Control RTEMS_Malloc_GC_list;
90
[e746a88]91/* rtems_id RTEMS_Malloc_Heap; */
[11290355]92size_t RTEMS_Malloc_Sbrk_amount;
[ac7d5ef0]93
[11290355]94#ifdef RTEMS_DEBUG
95#define MALLOC_STATS
[1f94ed6b]96#define MALLOC_DIRTY
[55d7626]97/*#define MALLOC_ARENA_CHECK
98void checkMallocArena(void); */
[ac7d5ef0]99#endif
100
[11290355]101#ifdef MALLOC_STATS
[dcec5a4]102#define MSBUMP(f,n)    rtems_malloc_stats.f += (n)
[11290355]103
104struct {
[83c5fc1]105    uint32_t    space_available;             /* current size of malloc area */
106    uint32_t    malloc_calls;                /* # calls to malloc */
107    uint32_t    free_calls;
108    uint32_t    realloc_calls;
109    uint32_t    calloc_calls;
110    uint32_t    max_depth;                   /* most ever malloc'd at 1 time */
[2751cbe0]111    uintmax_t    lifetime_allocated;
112    uintmax_t    lifetime_freed;
[dcec5a4]113} rtems_malloc_stats;
[11290355]114
[dcec5a4]115#else                   /* No rtems_malloc_stats */
[11290355]116#define MSBUMP(f,n)
117#endif
[ac7d5ef0]118
119void RTEMS_Malloc_Initialize(
120  void   *start,
121  size_t  length,
122  size_t  sbrk_amount
123)
124{
[e746a88]125  uint32_t      status;
126  void         *starting_address;
127  uintptr_t     old_address;
128  uintptr_t     uaddress;
[ac7d5ef0]129
[aab4664d]130  /*
131   *  Initialize the garbage collection list to start with nothing on it.
132   */
133  Chain_Initialize_empty(&RTEMS_Malloc_GC_list);
134
[ac7d5ef0]135  /*
136   * If the starting address is 0 then we are to attempt to
137   * get length worth of memory using sbrk. Make sure we
138   * align the address that we get back.
139   */
140
141  starting_address = start;
[e8512eb]142  RTEMS_Malloc_Sbrk_amount = sbrk_amount;
[ac7d5ef0]143
144  if (!starting_address) {
[b3ee778e]145    uaddress = (uintptr_t)sbrk(length);
[ac7d5ef0]146
[b3ee778e]147    if (uaddress == (uintptr_t) -1) {
[ac7d5ef0]148      rtems_fatal_error_occurred( RTEMS_NO_MEMORY );
149      /* DOES NOT RETURN!!! */
150    }
151
[b3ee778e]152    if (uaddress & (CPU_HEAP_ALIGNMENT-1)) {
153      old_address = uaddress;
154      uaddress = (uaddress + CPU_HEAP_ALIGNMENT) & ~(CPU_HEAP_ALIGNMENT-1);
[4cc631db]155
[11290355]156       /*
157        * adjust the length by whatever we aligned by
158        */
[4cc631db]159
[b3ee778e]160      length -= uaddress - old_address;
[ac7d5ef0]161    }
162
[b3ee778e]163    starting_address = (void *)uaddress;
[ac7d5ef0]164  }
165
[3b93a2de]166  /*
167   *  If the BSP is not clearing out the workspace, then it is most likely
[50f32b11]168   *  not clearing out the initial memory for the heap.  There is no
[3b93a2de]169   *  standard supporting zeroing out the heap memory.  But much code
170   *  with UNIX history seems to assume that memory malloc'ed during
171   *  initialization (before any free's) is zero'ed.  This is true most
172   *  of the time under UNIX because zero'ing memory when it is first
173   *  given to a process eliminates the chance of a process seeing data
174   *  left over from another process.  This would be a security violation.
175   */
176
[458bd34]177  if ( rtems_cpu_configuration_get_do_zero_of_workspace() )
[3b93a2de]178     memset( starting_address, 0, length );
179
[ac7d5ef0]180  /*
181   *  Unfortunately we cannot use assert if this fails because if this
182   *  has failed we do not have a heap and if we do not have a heap
183   *  STDIO cannot work because there will be no buffers.
184   */
185
[e746a88]186  status = _Protected_heap_Initialize(
187    &RTEMS_Malloc_Heap,
[ac7d5ef0]188    starting_address,
189    length,
[e746a88]190    CPU_HEAP_ALIGNMENT
[ac7d5ef0]191  );
[e746a88]192  if ( !status )
[ac7d5ef0]193    rtems_fatal_error_occurred( status );
[11290355]194
195#ifdef MALLOC_STATS
196  /* zero all the stats */
[07a3253d]197  (void) memset( &rtems_malloc_stats, 0, sizeof(rtems_malloc_stats) );
[11290355]198#endif
[50f32b11]199
[11290355]200  MSBUMP(space_available, length);
[ac7d5ef0]201}
202
[1f2d5df]203#ifdef RTEMS_NEWLIB
[ac7d5ef0]204void *malloc(
205  size_t  size
206)
207{
[e746a88]208  void        *return_this;
209  void        *starting_address;
[83c5fc1]210  uint32_t     the_size;
211  uint32_t     sbrk_amount;
[e746a88]212  Chain_Node  *to_be_freed;
[ac7d5ef0]213
[11290355]214  MSBUMP(malloc_calls, 1);
215
[ac7d5ef0]216  if ( !size )
217    return (void *) 0;
218
[aab4664d]219  /*
220   *  Do not attempt to allocate memory if in a critical section or ISR.
221   */
222
[690861c]223  if (_System_state_Is_up(_System_state_Get())) {
224    if (_Thread_Dispatch_disable_level > 0)
225      return (void *) 0;
[50f32b11]226
[690861c]227    if (_ISR_Nest_level > 0)
228      return (void *) 0;
229  }
[50f32b11]230
[aab4664d]231  /*
232   *  If some free's have been deferred, then do them now.
233   */
234  while ((to_be_freed = Chain_Get(&RTEMS_Malloc_GC_list)) != NULL)
235    free(to_be_freed);
236
[ac7d5ef0]237  /*
[e746a88]238   * Try to give a segment in the current heap if there is not
239   * enough space then try to grow the heap.
[ac7d5ef0]240   * If this fails then return a NULL pointer.
241   */
242
[be31de7]243#ifdef MALLOC_ARENA_CHECK
244  size += sizeof(struct mallocNode) + SENTINELSIZE;
245#endif
[e746a88]246  return_this = _Protected_heap_Allocate( &RTEMS_Malloc_Heap, size );
[ac7d5ef0]247
[e746a88]248  if ( !return_this ) {
[ac7d5ef0]249    /*
250     *  Round to the "requested sbrk amount" so hopefully we won't have
251     *  to grow again for a while.  This effectively does sbrk() calls
252     *  in "page" amounts.
253     */
254
255    sbrk_amount = RTEMS_Malloc_Sbrk_amount;
256
257    if ( sbrk_amount == 0 )
258      return (void *) 0;
259
260    the_size = ((size + sbrk_amount) / sbrk_amount * sbrk_amount);
261
[50f32b11]262    if ((starting_address = (void *)sbrk(the_size))
[e7ceef91]263            == (void*) -1)
[ac7d5ef0]264      return (void *) 0;
265
[e746a88]266    if ( !_Protected_heap_Extend(
267            &RTEMS_Malloc_Heap, starting_address, the_size) ) {
[ac7d5ef0]268      sbrk(-the_size);
269      errno = ENOMEM;
270      return (void *) 0;
271    }
[50f32b11]272
[11290355]273    MSBUMP(space_available, the_size);
274
[e746a88]275    return_this = _Protected_heap_Allocate( &RTEMS_Malloc_Heap, size );
276    if ( !return_this ) {
[ac7d5ef0]277      errno = ENOMEM;
278      return (void *) 0;
279    }
280  }
281
[11290355]282#ifdef MALLOC_STATS
283  if (return_this)
284  {
[e746a88]285      size_t     actual_size = 0;
[83c5fc1]286      uint32_t   current_depth;
[55d7626]287      void      *ptr = return_this;
288      _Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &actual_size);
[289ad86]289      MSBUMP(lifetime_allocated, actual_size);
[07a3253d]290      current_depth = rtems_malloc_stats.lifetime_allocated -
291                   rtems_malloc_stats.lifetime_freed;
[dcec5a4]292      if (current_depth > rtems_malloc_stats.max_depth)
293          rtems_malloc_stats.max_depth = current_depth;
[11290355]294  }
295#endif
[1f94ed6b]296
297#ifdef MALLOC_DIRTY
298  (void) memset(return_this, 0xCF, size);
299#endif
300
[be31de7]301#ifdef MALLOC_ARENA_CHECK
302  {
303  struct mallocNode *mp = (struct mallocNode *)return_this;
304  int key, *fp, *nfp, i;
305  rtems_interrupt_disable(key);
306  mp->memory = mp + 1;
307  return_this = mp->memory;
308  mp->size = size - (sizeof(struct mallocNode) + SENTINELSIZE);
309  fp = (int *)&size - 2;
310  for (i = 0 ; i < CALLCHAINSIZE ; i++) {
311    mp->callChain[i] = fp[1];
312    nfp = (int *)(fp[0]);
313    if((nfp <= fp) || (nfp > (int *)(1 << 24)))
314     break;
315    fp = nfp;
316  }
317  while (i < CALLCHAINSIZE)
318    mp->callChain[i++] = 0;
319  memcpy((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE);
320  mp->forw = mallocNodeHead.forw;
321  mp->back = &mallocNodeHead;
322  mallocNodeHead.forw->back = mp;
323  mallocNodeHead.forw = mp;
324  rtems_interrupt_enable(key);
325  }
326#endif
[ac7d5ef0]327  return return_this;
328}
329
330void *calloc(
331  size_t nelem,
332  size_t elsize
333)
334{
335  register char *cptr;
336  int length;
337
[11290355]338  MSBUMP(calloc_calls, 1);
339
[ac7d5ef0]340  length = nelem * elsize;
341  cptr = malloc( length );
342  if ( cptr )
343    memset( cptr, '\0', length );
344
[1f94ed6b]345  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
346
[ac7d5ef0]347  return cptr;
348}
349
350void *realloc(
351  void *ptr,
352  size_t size
353)
354{
[e7ceef91]355  size_t old_size;
[ac7d5ef0]356  char *new_area;
357
[11290355]358  MSBUMP(realloc_calls, 1);
359
[aab4664d]360  /*
361   *  Do not attempt to allocate memory if in a critical section or ISR.
362   */
363
[690861c]364  if (_System_state_Is_up(_System_state_Get())) {
365    if (_Thread_Dispatch_disable_level > 0)
366      return (void *) 0;
[50f32b11]367
[690861c]368    if (_ISR_Nest_level > 0)
369      return (void *) 0;
370  }
[50f32b11]371
[aab4664d]372  /*
[80f2885b]373   * Continue with realloc().
[aab4664d]374   */
[ac7d5ef0]375  if ( !ptr )
376    return malloc( size );
377
378  if ( !size ) {
379    free( ptr );
380    return (void *) 0;
381  }
382
[be31de7]383#ifdef MALLOC_ARENA_CHECK
384  {
[e746a88]385    void *np;
386    np = malloc(size);
387    if (!np) return np;
388    memcpy(np,ptr,size);
389    free(ptr);
390    return np;
[be31de7]391  }
392#endif
[e746a88]393  if ( _Protected_heap_Resize_block( &RTEMS_Malloc_Heap, ptr, size ) ) {
[80f2885b]394    return ptr;
395  }
396
[ac7d5ef0]397  new_area = malloc( size );
[50f32b11]398
[8b2ecf85]399  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
400
[d9c3805]401  /*
[50f32b11]402   *  There used to be a free on this error case but it is wrong to
[d9c3805]403   *  free the memory per OpenGroup Single UNIX Specification V2
404   *  and the C Standard.
405   */
406
[ac7d5ef0]407  if ( !new_area ) {
408    return (void *) 0;
409  }
410
[e746a88]411  if ( !_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &old_size) ) {
[11290355]412    errno = EINVAL;
413    return (void *) 0;
414  }
415
[ac7d5ef0]416  memcpy( new_area, ptr, (size < old_size) ? size : old_size );
417  free( ptr );
418
419  return new_area;
420
421}
422
423void free(
424  void *ptr
425)
426{
[11290355]427  MSBUMP(free_calls, 1);
428
[ac7d5ef0]429  if ( !ptr )
430    return;
431
[aab4664d]432  /*
433   *  Do not attempt to free memory if in a critical section or ISR.
434   */
435
[690861c]436  if (_System_state_Is_up(_System_state_Get())) {
437    if ((_Thread_Dispatch_disable_level > 0) || (_ISR_Nest_level > 0)) {
438      Chain_Append(&RTEMS_Malloc_GC_list, (Chain_Node *)ptr);
439      return;
440    }
[aab4664d]441  }
[50f32b11]442
[be31de7]443#ifdef MALLOC_ARENA_CHECK
444  {
445  struct mallocNode *mp = (struct mallocNode *)ptr - 1;
446  struct mallocNode *mp1;
447  int key;
448  rtems_interrupt_disable(key);
449  if ((mp->memory != (mp + 1))
450   || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0))
451    reportMallocError("Freeing with inconsistent pointer/sentinel", mp);
452  mp1 = mallocNodeHead.forw;
453  while (mp1 != &mallocNodeHead) {
454    if (mp1 == mp)
455      break;
456    mp1 = mp1->forw;
457  }
458  if (mp1 != mp)
459    reportMallocError("Freeing, but not on allocated list", mp);
460  mp->forw->back = mp->back;
461  mp->back->forw = mp->forw;
462  mp->back = mp->forw = NULL;
463  ptr = mp;
464  rtems_interrupt_enable(key);
465  }
466#endif
[11290355]467#ifdef MALLOC_STATS
468  {
[e746a88]469    size_t size;
[55d7626]470    if (_Protected_heap_Get_block_size(&RTEMS_Malloc_Heap, ptr, &size) ) {
[e746a88]471      MSBUMP(lifetime_freed, size);
472    }
[11290355]473  }
474#endif
[50f32b11]475
[e746a88]476  if ( !_Protected_heap_Free( &RTEMS_Malloc_Heap, ptr ) ) {
[ac7d5ef0]477    errno = EINVAL;
478    assert( 0 );
479  }
480}
[be31de7]481
482#ifdef MALLOC_ARENA_CHECK
483void checkMallocArena(void)
484{
485    struct mallocNode *mp = mallocNodeHead.forw;
486    int key;
487    rtems_interrupt_disable(key);
488    while (mp != &mallocNodeHead) {
489        if ((mp->forw->back != mp)
490         || (mp->back->forw != mp))
491            reportMallocError("Pointers mangled", mp);
492        if((mp->memory != (mp + 1))
493         || (memcmp((char *)mp->memory + mp->size, SENTINEL, SENTINELSIZE) != 0))
494            reportMallocError("Inconsistent pointer/sentinel", mp);
495        mp = mp->forw;
496    }
497    rtems_interrupt_enable(key);
498}
499#endif
500
[1f2d5df]501/* end if RTEMS_NEWLIB */
502#endif
[ac7d5ef0]503
[11290355]504#ifdef MALLOC_STATS
505/*
506 * Dump the malloc statistics
507 * May be called via atexit()  (installable by our bsp) or
508 * at any time by user
509 */
510
511void malloc_dump(void)
512{
[83c5fc1]513    uint32_t   allocated = rtems_malloc_stats.lifetime_allocated -
[07a3253d]514                     rtems_malloc_stats.lifetime_freed;
[11290355]515
516    printf("Malloc stats\n");
[2751cbe0]517    printf("  avail:%"PRIu32"k  allocated:%"PRIu32"k (%"PRId32"%%) "
518              "max:%"PRIu32"k (%"PRIu32"%%)"
519              " lifetime:%"PRIuMAX"k freed:%"PRIuMAX"k\n",
520           rtems_malloc_stats.space_available / 1024,
521           allocated / 1024,
[11290355]522           /* avoid float! */
[dcec5a4]523           (allocated * 100) / rtems_malloc_stats.space_available,
[2751cbe0]524           rtems_malloc_stats.max_depth / 1024,
[dcec5a4]525           (rtems_malloc_stats.max_depth * 100) / rtems_malloc_stats.space_available,
[2751cbe0]526           rtems_malloc_stats.lifetime_allocated / 1024,
527           rtems_malloc_stats.lifetime_freed / 1024
528           );
529    printf("  Call counts:   malloc:%"PRIu32"   free:%"PRIu32"   realloc:%"PRIu32"   calloc:%"PRIu32"\n",
[dcec5a4]530           rtems_malloc_stats.malloc_calls,
531           rtems_malloc_stats.free_calls,
532           rtems_malloc_stats.realloc_calls,
533           rtems_malloc_stats.calloc_calls);
[1f2d5df]534}
535
536
537void malloc_walk(size_t source, size_t printf_enabled)
538{
[e746a88]539  _Protected_heap_Walk( &RTEMS_Malloc_Heap, source, printf_enabled );
[1f2d5df]540}
541
542#else
543
544void malloc_dump(void)
545{
546   return;
547}
[50f32b11]548
[1f2d5df]549void malloc_walk(size_t source, size_t printf_enabled)
550{
551   return;
552}
553
[11290355]554#endif
555
[ac7d5ef0]556/*
557 *  "Reentrant" versions of the above routines implemented above.
558 */
559
560#ifdef RTEMS_NEWLIB
[388be68f]561void *_malloc_r(
[ac7d5ef0]562  struct _reent *ignored,
563  size_t  size
564)
565{
566  return malloc( size );
567}
568
[388be68f]569void *_calloc_r(
570  struct _reent *ignored,
[ac7d5ef0]571  size_t nelem,
572  size_t elsize
573)
574{
575  return calloc( nelem, elsize );
576}
577
[388be68f]578void *_realloc_r(
579  struct _reent *ignored,
[ac7d5ef0]580  void *ptr,
581  size_t size
582)
583{
[388be68f]584  return realloc( ptr, size );
[ac7d5ef0]585}
586
[388be68f]587void _free_r(
588  struct _reent *ignored,
[ac7d5ef0]589  void *ptr
590)
591{
592  free( ptr );
593}
[8ef3818]594
[ac7d5ef0]595#endif
Note: See TracBrowser for help on using the repository browser.