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