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