Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 2002-2012, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File cmemory.c      ICU Heap allocation.
     10 *                     All ICU heap allocation, both for C and C++ new of ICU
     11 *                     class types, comes through these functions.
     12 *
     13 *                     If you have a need to replace ICU allocation, this is the
     14 *                     place to do it.
     15 *
     16 *                     Note that uprv_malloc(0) returns a non-NULL pointer, and
     17 *                     that a subsequent free of that pointer value is a NOP.
     18 *
     19 ******************************************************************************
     20 */
     21 #include "unicode/uclean.h"
     22 #include "cmemory.h"
     23 #include "putilimp.h"
     24 #include "uassert.h"
     25 #include <stdlib.h>
     26 
     27 /* uprv_malloc(0) returns a pointer to this read-only data. */
     28 static const int32_t zeroMem[] = {0, 0, 0, 0, 0, 0};
     29 
     30 /* Function Pointers for user-supplied heap functions  */
     31 static const void     *pContext;
     32 static UMemAllocFn    *pAlloc;
     33 static UMemReallocFn  *pRealloc;
     34 static UMemFreeFn     *pFree;
     35 
     36 /* Flag indicating whether any heap allocations have happened.
     37  *   Used to prevent changing out the heap functions after allocations have been made */
     38 static UBool   gHeapInUse;
     39 
     40 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     41 #include <stdio.h>
     42 static int n=0;
     43 static long b=0;
     44 #endif
     45 
     46 #if U_DEBUG
     47 
     48 static char gValidMemorySink = 0;
     49 
     50 U_CAPI void uprv_checkValidMemory(const void *p, size_t n) {
     51     /*
     52      * Access the memory to ensure that it's all valid.
     53      * Load and save a computed value to try to ensure that the compiler
     54      * does not throw away the whole loop.
     55      * A thread analyzer might complain about un-mutexed access to gValidMemorySink
     56      * which is true but harmless because no one ever uses the value in gValidMemorySink.
     57      */
     58     const char *s = (const char *)p;
     59     char c = gValidMemorySink;
     60     size_t i;
     61     U_ASSERT(p != NULL);
     62     for(i = 0; i < n; ++i) {
     63         c ^= s[i];
     64     }
     65     gValidMemorySink = c;
     66 }
     67 
     68 #endif  /* U_DEBUG */
     69 
     70 U_CAPI void * U_EXPORT2
     71 uprv_malloc(size_t s) {
     72 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     73 #if 1
     74   putchar('>');
     75   fflush(stdout);
     76 #else
     77   fprintf(stderr,"MALLOC\t#%d\t%ul bytes\t%ul total\n", ++n,s,(b+=s)); fflush(stderr);
     78 #endif
     79 #endif
     80     if (s > 0) {
     81         gHeapInUse = TRUE;
     82         if (pAlloc) {
     83             return (*pAlloc)(pContext, s);
     84         } else {
     85             return uprv_default_malloc(s);
     86         }
     87     } else {
     88         return (void *)zeroMem;
     89     }
     90 }
     91 
     92 U_CAPI void * U_EXPORT2
     93 uprv_realloc(void * buffer, size_t size) {
     94 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     95   putchar('~');
     96   fflush(stdout);
     97 #endif
     98     if (buffer == zeroMem) {
     99         return uprv_malloc(size);
    100     } else if (size == 0) {
    101         if (pFree) {
    102             (*pFree)(pContext, buffer);
    103         } else {
    104             uprv_default_free(buffer);
    105         }
    106         return (void *)zeroMem;
    107     } else {
    108         gHeapInUse = TRUE;
    109         if (pRealloc) {
    110             return (*pRealloc)(pContext, buffer, size);
    111         } else {
    112             return uprv_default_realloc(buffer, size);
    113         }
    114     }
    115 }
    116 
    117 U_CAPI void U_EXPORT2
    118 uprv_free(void *buffer) {
    119 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    120   putchar('<');
    121   fflush(stdout);
    122 #endif
    123     if (buffer != zeroMem) {
    124         if (pFree) {
    125             (*pFree)(pContext, buffer);
    126         } else {
    127             uprv_default_free(buffer);
    128         }
    129     }
    130 }
    131 
    132 U_CAPI void * U_EXPORT2
    133 uprv_calloc(size_t num, size_t size) {
    134     void *mem = NULL;
    135     size *= num;
    136     mem = uprv_malloc(size);
    137     if (mem) {
    138         uprv_memset(mem, 0, size);
    139     }
    140     return mem;
    141 }
    142 
    143 U_CAPI void U_EXPORT2
    144 u_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f,  UErrorCode *status)
    145 {
    146     if (U_FAILURE(*status)) {
    147         return;
    148     }
    149     if (a==NULL || r==NULL || f==NULL) {
    150         *status = U_ILLEGAL_ARGUMENT_ERROR;
    151         return;
    152     }
    153     if (gHeapInUse) {
    154         *status = U_INVALID_STATE_ERROR;
    155         return;
    156     }
    157     pContext  = context;
    158     pAlloc    = a;
    159     pRealloc  = r;
    160     pFree     = f;
    161 }
    162 
    163 
    164 U_CFUNC UBool cmemory_cleanup(void) {
    165     pContext   = NULL;
    166     pAlloc     = NULL;
    167     pRealloc   = NULL;
    168     pFree      = NULL;
    169     gHeapInUse = FALSE;
    170     return TRUE;
    171 }
    172 
    173 
    174 /*
    175  *   gHeapInUse
    176  *       Return True if ICU has allocated any memory.
    177  *       Used by u_SetMutexFunctions() and similar to verify that ICU has not
    178  *               been used, that it is in a pristine initial state.
    179  */
    180 U_CFUNC UBool cmemory_inUse() {
    181     return gHeapInUse;
    182 }
    183 
    184