• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
uprv_checkValidMemory(const void * p,size_t n)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
uprv_malloc(size_t s)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
uprv_realloc(void * buffer,size_t size)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
uprv_free(void * buffer)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
uprv_calloc(size_t num,size_t size)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
u_setMemoryFunctions(const void * context,UMemAllocFn * a,UMemReallocFn * r,UMemFreeFn * f,UErrorCode * status)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 
cmemory_cleanup(void)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  */
cmemory_inUse()180 U_CFUNC UBool cmemory_inUse() {
181     return gHeapInUse;
182 }
183 
184