1// Copyright (C) 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. */ 30static const int32_t zeroMem[] = {0, 0, 0, 0, 0, 0}; 31 32/* Function Pointers for user-supplied heap functions */ 33static const void *pContext; 34static UMemAllocFn *pAlloc; 35static UMemReallocFn *pRealloc; 36static UMemFreeFn *pFree; 37 38#if U_DEBUG && defined(UPRV_MALLOC_COUNT) 39#include <stdio.h> 40static int n=0; 41static long b=0; 42#endif 43 44#if U_DEBUG 45 46static char gValidMemorySink = 0; 47 48U_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 68U_CAPI void * U_EXPORT2 69uprv_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 89U_CAPI void * U_EXPORT2 90uprv_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 113U_CAPI void U_EXPORT2 114uprv_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 128U_CAPI void * U_EXPORT2 129uprv_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 139U_CAPI void U_EXPORT2 140u_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 156U_CFUNC UBool cmemory_cleanup(void) { 157 pContext = NULL; 158 pAlloc = NULL; 159 pRealloc = NULL; 160 pFree = NULL; 161 return TRUE; 162} 163