1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 2003-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8 /*
9 * File hpmufn.c
10 *
11 */
12
13 #include "unicode/utypes.h"
14 #include "unicode/putil.h"
15 #include "unicode/uclean.h"
16 #include "unicode/uchar.h"
17 #include "unicode/ures.h"
18 #include "cintltst.h"
19 #include "unicode/utrace.h"
20 #include <stdlib.h>
21 #include <string.h>
22
23 /**
24 * This should align the memory properly on any machine.
25 */
26 typedef union {
27 long t1;
28 double t2;
29 void *t3;
30 } ctest_AlignedMemory;
31
32 static void TestHeapFunctions(void);
33
34 void addHeapMutexTest(TestNode **root);
35
36
37 void
addHeapMutexTest(TestNode ** root)38 addHeapMutexTest(TestNode** root)
39 {
40 addTest(root, &TestHeapFunctions, "hpmufn/TestHeapFunctions" );
41 }
42
43 static int32_t gMutexFailures = 0;
44
45 #define TEST_STATUS(status, expected) \
46 if (status != expected) { \
47 log_err_status(status, "FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \
48 __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; }
49
50
51 #define TEST_ASSERT(expr) \
52 if (!(expr)) { \
53 log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \
54 gMutexFailures++; \
55 }
56
57
58 /* These tests do cleanup and reinitialize ICU in the course of their operation.
59 * The ICU data directory must be preserved across these operations.
60 * Here is a helper function to assist with that.
61 */
safeGetICUDataDirectory()62 static char *safeGetICUDataDirectory() {
63 const char *dataDir = u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
64 char *retStr = NULL;
65 if (dataDir != NULL) {
66 retStr = (char *)malloc(strlen(dataDir)+1);
67 strcpy(retStr, dataDir);
68 }
69 return retStr;
70 }
71
72
73
74 /*
75 * Test Heap Functions.
76 * Implemented on top of the standard malloc heap.
77 * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
78 * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
79 * ends up being freed directly, without coming through us.
80 * Allocations are counted, to check that ICU actually does call back to us.
81 */
82 int gBlockCount = 0;
83 const void *gContext;
84
myMemAlloc(const void * context,size_t size)85 static void * U_CALLCONV myMemAlloc(const void *context, size_t size) {
86 char *retPtr = (char *)malloc(size+sizeof(ctest_AlignedMemory));
87 if (retPtr != NULL) {
88 retPtr += sizeof(ctest_AlignedMemory);
89 }
90 gBlockCount ++;
91 return retPtr;
92 }
93
myMemFree(const void * context,void * mem)94 static void U_CALLCONV myMemFree(const void *context, void *mem) {
95 char *freePtr = (char *)mem;
96 if (freePtr != NULL) {
97 freePtr -= sizeof(ctest_AlignedMemory);
98 }
99 free(freePtr);
100 }
101
102
103
myMemRealloc(const void * context,void * mem,size_t size)104 static void * U_CALLCONV myMemRealloc(const void *context, void *mem, size_t size) {
105 char *p = (char *)mem;
106 char *retPtr;
107
108 if (p!=NULL) {
109 p -= sizeof(ctest_AlignedMemory);
110 }
111 retPtr = realloc(p, size+sizeof(ctest_AlignedMemory));
112 if (retPtr != NULL) {
113 p += sizeof(ctest_AlignedMemory);
114 }
115 return retPtr;
116 }
117
118
TestHeapFunctions()119 static void TestHeapFunctions() {
120 UErrorCode status = U_ZERO_ERROR;
121 UResourceBundle *rb = NULL;
122 char *icuDataDir;
123 UVersionInfo unicodeVersion = {0,0,0,0};
124
125 icuDataDir = safeGetICUDataDirectory(); /* save icu data dir, so we can put it back
126 * after doing u_cleanup(). */
127
128
129 /* Verify that ICU can be cleaned up and reinitialized successfully.
130 * Failure here usually means that some ICU service didn't clean up successfully,
131 * probably because some earlier test accidently left something open. */
132 ctest_resetICU();
133
134 /* Un-initialize ICU */
135 u_cleanup();
136
137 /* Can not set memory functions with NULL values */
138 status = U_ZERO_ERROR;
139 u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status);
140 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
141 status = U_ZERO_ERROR;
142 u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status);
143 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
144 status = U_ZERO_ERROR;
145 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status);
146 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
147
148 /* u_setMemoryFunctions() should work with null or non-null context pointer */
149 status = U_ZERO_ERROR;
150 u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
151 TEST_STATUS(status, U_ZERO_ERROR);
152 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
153 TEST_STATUS(status, U_ZERO_ERROR);
154
155
156 /* After reinitializing ICU, we can not set the memory funcs again. */
157 status = U_ZERO_ERROR;
158 u_setDataDirectory(icuDataDir);
159 u_init(&status);
160 TEST_STATUS(status, U_ZERO_ERROR);
161
162 /* Doing ICU operations should cause allocations to come through our test heap */
163 gBlockCount = 0;
164 status = U_ZERO_ERROR;
165 rb = ures_open(NULL, "es", &status);
166 TEST_STATUS(status, U_ZERO_ERROR);
167 if (gBlockCount == 0) {
168 log_err("Heap functions are not being called from ICU.\n");
169 }
170 ures_close(rb);
171
172 /* Cleanup should put the heap back to its default implementation. */
173 ctest_resetICU();
174 u_getUnicodeVersion(unicodeVersion);
175 if (unicodeVersion[0] <= 0) {
176 log_err("Properties doesn't reinitialize without u_init.\n");
177 }
178 status = U_ZERO_ERROR;
179 u_init(&status);
180 TEST_STATUS(status, U_ZERO_ERROR);
181
182 /* ICU operations should no longer cause allocations to come through our test heap */
183 gBlockCount = 0;
184 status = U_ZERO_ERROR;
185 rb = ures_open(NULL, "fr", &status);
186 TEST_STATUS(status, U_ZERO_ERROR);
187 if (gBlockCount != 0) {
188 log_err("Heap functions did not reset after u_cleanup.\n");
189 }
190 ures_close(rb);
191 free(icuDataDir);
192
193 ctest_resetICU();
194 }
195
196
197