1// © 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-nullptr pointer,
19* and 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
44U_CAPI void * U_EXPORT2
45uprv_malloc(size_t s) {
46#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
47#if 1
48 putchar('>');
49 fflush(stdout);
50#else
51 fprintf(stderr,"MALLOC\t#%d\t%ul bytes\t%ul total\n", ++n,s,(b+=s)); fflush(stderr);
52#endif
53#endif
54 if (s > 0) {
55 if (pAlloc) {
56 return (*pAlloc)(pContext, s);
57 } else {
58 return uprv_default_malloc(s);
59 }
60 } else {
61 return (void *)zeroMem;
62 }
63}
64
65U_CAPI void * U_EXPORT2
66uprv_realloc(void * buffer, size_t size) {
67#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
68 putchar('~');
69 fflush(stdout);
70#endif
71 if (buffer == zeroMem) {
72 return uprv_malloc(size);
73 } else if (size == 0) {
74 if (pFree) {
75 (*pFree)(pContext, buffer);
76 } else {
77 uprv_default_free(buffer);
78 }
79 return (void *)zeroMem;
80 } else {
81 if (pRealloc) {
82 return (*pRealloc)(pContext, buffer, size);
83 } else {
84 return uprv_default_realloc(buffer, size);
85 }
86 }
87}
88
89U_CAPI void U_EXPORT2
90uprv_free(void *buffer) {
91#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
92 putchar('<');
93 fflush(stdout);
94#endif
95 if (buffer != zeroMem) {
96 if (pFree) {
97 (*pFree)(pContext, buffer);
98 } else {
99 uprv_default_free(buffer);
100 }
101 }
102}
103
104U_CAPI void * U_EXPORT2
105uprv_calloc(size_t num, size_t size) {
106 void *mem = nullptr;
107 size *= num;
108 mem = uprv_malloc(size);
109 if (mem) {
110 uprv_memset(mem, 0, size);
111 }
112 return mem;
113}
114
115U_CAPI void U_EXPORT2
116u_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f, UErrorCode *status)
117{
118 if (U_FAILURE(*status)) {
119 return;
120 }
121 if (a==nullptr || r==nullptr || f==nullptr) {
122 *status = U_ILLEGAL_ARGUMENT_ERROR;
123 return;
124 }
125 pContext = context;
126 pAlloc = a;
127 pRealloc = r;
128 pFree = f;
129}
130
131
132U_CFUNC UBool cmemory_cleanup() {
133 pContext = nullptr;
134 pAlloc = nullptr;
135 pRealloc = nullptr;
136 pFree = nullptr;
137 return true;
138}
139