OLD | NEW |
| (Empty) |
1 /******************************************************************** | |
2 * COPYRIGHT: | |
3 * Copyright (c) 2003-2015, 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 | |
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)); gMutexFailure
s++; } | |
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 */ | |
60 static char *safeGetICUDataDirectory() { | |
61 const char *dataDir = u_getDataDirectory(); /* Returned string vanashes wit
h 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 | |
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 | |
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 | |
102 static void * U_CALLCONV myMemRealloc(const void *context, void *mem, size_t siz
e) { | |
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 | |
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 pu
t 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 success
fully, | |
129 * probably because some earlier test accidently left something open. */ | |
130 ctest_resetICU(); | |
131 | |
132 /* Un-initialize ICU */ | |
133 u_cleanup(); | |
134 | |
135 /* Can not set memory functions with NULL values */ | |
136 status = U_ZERO_ERROR; | |
137 u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status); | |
138 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); | |
139 status = U_ZERO_ERROR; | |
140 u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status); | |
141 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); | |
142 status = U_ZERO_ERROR; | |
143 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status); | |
144 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); | |
145 | |
146 /* u_setMemoryFunctions() should work with null or non-null context pointer
*/ | |
147 status = U_ZERO_ERROR; | |
148 u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status); | |
149 TEST_STATUS(status, U_ZERO_ERROR); | |
150 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status
); | |
151 TEST_STATUS(status, U_ZERO_ERROR); | |
152 | |
153 | |
154 /* After reinitializing ICU, we can not set the memory funcs again. */ | |
155 status = U_ZERO_ERROR; | |
156 u_setDataDirectory(icuDataDir); | |
157 u_init(&status); | |
158 TEST_STATUS(status, U_ZERO_ERROR); | |
159 | |
160 /* Doing ICU operations should cause allocations to come through our test he
ap */ | |
161 gBlockCount = 0; | |
162 status = U_ZERO_ERROR; | |
163 rb = ures_open(NULL, "es", &status); | |
164 TEST_STATUS(status, U_ZERO_ERROR); | |
165 if (gBlockCount == 0) { | |
166 log_err("Heap functions are not being called from ICU.\n"); | |
167 } | |
168 ures_close(rb); | |
169 | |
170 /* Cleanup should put the heap back to its default implementation. */ | |
171 ctest_resetICU(); | |
172 u_getUnicodeVersion(unicodeVersion); | |
173 if (unicodeVersion[0] <= 0) { | |
174 log_err("Properties doesn't reinitialize without u_init.\n"); | |
175 } | |
176 status = U_ZERO_ERROR; | |
177 u_init(&status); | |
178 TEST_STATUS(status, U_ZERO_ERROR); | |
179 | |
180 /* ICU operations should no longer cause allocations to come through our tes
t heap */ | |
181 gBlockCount = 0; | |
182 status = U_ZERO_ERROR; | |
183 rb = ures_open(NULL, "fr", &status); | |
184 TEST_STATUS(status, U_ZERO_ERROR); | |
185 if (gBlockCount != 0) { | |
186 log_err("Heap functions did not reset after u_cleanup.\n"); | |
187 } | |
188 ures_close(rb); | |
189 free(icuDataDir); | |
190 | |
191 ctest_resetICU(); | |
192 } | |
193 | |
194 | |
OLD | NEW |