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 
uprv_checkValidMemory(const void * p,size_t n)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
uprv_malloc(size_t s)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
uprv_realloc(void * buffer,size_t size)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
uprv_free(void * buffer)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
uprv_calloc(size_t num,size_t size)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
u_setMemoryFunctions(const void * context,UMemAllocFn * a,UMemReallocFn * r,UMemFreeFn * f,UErrorCode * status)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 
cmemory_cleanup(void)154 U_CFUNC UBool cmemory_cleanup(void) {
155     pContext   = NULL;
156     pAlloc     = NULL;
157     pRealloc   = NULL;
158     pFree      = NULL;
159     return TRUE;
160 }
161