Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 2002-2015, 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 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     37 #include <stdio.h>
     38 static int n=0;
     39 static long b=0;
     40 #endif
     41 
     42 #if U_DEBUG
     43 
     44 static char gValidMemorySink = 0;
     45 
     46 U_CAPI void uprv_checkValidMemory(const void *p, size_t n) {
     47     /*
     48      * Access the memory to ensure that it's all valid.
     49      * Load and save a computed value to try to ensure that the compiler
     50      * does not throw away the whole loop.
     51      * A thread analyzer might complain about un-mutexed access to gValidMemorySink
     52      * which is true but harmless because no one ever uses the value in gValidMemorySink.
     53      */
     54     const char *s = (const char *)p;
     55     char c = gValidMemorySink;
     56     size_t i;
     57     U_ASSERT(p != NULL);
     58     for(i = 0; i < n; ++i) {
     59         c ^= s[i];
     60     }
     61     gValidMemorySink = c;
     62 }
     63 
     64 #endif  /* U_DEBUG */
     65 
     66 U_CAPI void * U_EXPORT2
     67 uprv_malloc(size_t s) {
     68 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     69 #if 1
     70   putchar('>');
     71   fflush(stdout);
     72 #else
     73   fprintf(stderr,"MALLOC\t#%d\t%ul bytes\t%ul total\n", ++n,s,(b+=s)); fflush(stderr);
     74 #endif
     75 #endif
     76     if (s > 0) {
     77         if (pAlloc) {
     78             return (*pAlloc)(pContext, s);
     79         } else {
     80             return uprv_default_malloc(s);
     81         }
     82     } else {
     83         return (void *)zeroMem;
     84     }
     85 }
     86 
     87 U_CAPI void * U_EXPORT2
     88 uprv_realloc(void * buffer, size_t size) {
     89 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
     90   putchar('~');
     91   fflush(stdout);
     92 #endif
     93     if (buffer == zeroMem) {
     94         return uprv_malloc(size);
     95     } else if (size == 0) {
     96         if (pFree) {
     97             (*pFree)(pContext, buffer);
     98         } else {
     99             uprv_default_free(buffer);
    100         }
    101         return (void *)zeroMem;
    102     } else {
    103         if (pRealloc) {
    104             return (*pRealloc)(pContext, buffer, size);
    105         } else {
    106             return uprv_default_realloc(buffer, size);
    107         }
    108     }
    109 }
    110 
    111 U_CAPI void U_EXPORT2
    112 uprv_free(void *buffer) {
    113 #if U_DEBUG && defined(UPRV_MALLOC_COUNT)
    114   putchar('<');
    115   fflush(stdout);
    116 #endif
    117     if (buffer != zeroMem) {
    118         if (pFree) {
    119             (*pFree)(pContext, buffer);
    120         } else {
    121             uprv_default_free(buffer);
    122         }
    123     }
    124 }
    125 
    126 U_CAPI void * U_EXPORT2
    127 uprv_calloc(size_t num, size_t size) {
    128     void *mem = NULL;
    129     size *= num;
    130     mem = uprv_malloc(size);
    131     if (mem) {
    132         uprv_memset(mem, 0, size);
    133     }
    134     return mem;
    135 }
    136 
    137 U_CAPI void U_EXPORT2
    138 u_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f,  UErrorCode *status)
    139 {
    140     if (U_FAILURE(*status)) {
    141         return;
    142     }
    143     if (a==NULL || r==NULL || f==NULL) {
    144         *status = U_ILLEGAL_ARGUMENT_ERROR;
    145         return;
    146     }
    147     pContext  = context;
    148     pAlloc    = a;
    149     pRealloc  = r;
    150     pFree     = f;
    151 }
    152 
    153 
    154 U_CFUNC UBool cmemory_cleanup(void) {
    155     pContext   = NULL;
    156     pAlloc     = NULL;
    157     pRealloc   = NULL;
    158     pFree      = NULL;
    159     return TRUE;
    160 }
    161