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. */
28static const int32_t zeroMem[] = {0, 0, 0, 0, 0, 0};
29
30/* Function Pointers for user-supplied heap functions  */
31static const void     *pContext;
32static UMemAllocFn    *pAlloc;
33static UMemReallocFn  *pRealloc;
34static 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 */
38static UBool   gHeapInUse;
39
40#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
41#include <stdio.h>
42static int n=0;
43static long b=0;
44#endif
45
46#if U_DEBUG
47
48static char gValidMemorySink = 0;
49
50U_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
70U_CAPI void * U_EXPORT2
71uprv_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
92U_CAPI void * U_EXPORT2
93uprv_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
117U_CAPI void U_EXPORT2
118uprv_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
132U_CAPI void * U_EXPORT2
133uprv_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
143U_CAPI void U_EXPORT2
144u_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
164U_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 */
180U_CFUNC UBool cmemory_inUse() {
181    return gHeapInUse;
182}
183
184