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