|
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 |