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