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