]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
374ca955 A |
3 | /******************************************************************** |
4 | * COPYRIGHT: | |
b331163b | 5 | * Copyright (c) 2003-2015, International Business Machines Corporation and |
374ca955 A |
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" | |
374ca955 A |
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); | |
374ca955 A |
33 | |
34 | void addHeapMutexTest(TestNode **root); | |
35 | ||
36 | ||
37 | void | |
38 | addHeapMutexTest(TestNode** root) | |
39 | { | |
46f4442e | 40 | addTest(root, &TestHeapFunctions, "hpmufn/TestHeapFunctions" ); |
374ca955 A |
41 | } |
42 | ||
43 | static int32_t gMutexFailures = 0; | |
44 | ||
45 | #define TEST_STATUS(status, expected) \ | |
46 | if (status != expected) { \ | |
729e4ab9 | 47 | log_err_status(status, "FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \ |
374ca955 A |
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 | */ | |
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 | ||
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 | ||
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 | ||
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 | ||
119 | static void TestHeapFunctions() { | |
120 | UErrorCode status = U_ZERO_ERROR; | |
121 | UResourceBundle *rb = NULL; | |
122 | char *icuDataDir; | |
73c04bcf | 123 | UVersionInfo unicodeVersion = {0,0,0,0}; |
374ca955 | 124 | |
374ca955 A |
125 | icuDataDir = safeGetICUDataDirectory(); /* save icu data dir, so we can put it back |
126 | * after doing u_cleanup(). */ | |
127 | ||
374ca955 | 128 | |
73c04bcf A |
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. */ | |
46f4442e | 132 | ctest_resetICU(); |
73c04bcf | 133 | |
374ca955 A |
134 | /* Un-initialize ICU */ |
135 | u_cleanup(); | |
374ca955 A |
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 | ||
b331163b | 156 | /* After reinitializing ICU, we can not set the memory funcs again. */ |
374ca955 A |
157 | status = U_ZERO_ERROR; |
158 | u_setDataDirectory(icuDataDir); | |
159 | u_init(&status); | |
160 | TEST_STATUS(status, U_ZERO_ERROR); | |
374ca955 A |
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. */ | |
46f4442e | 173 | ctest_resetICU(); |
73c04bcf A |
174 | u_getUnicodeVersion(unicodeVersion); |
175 | if (unicodeVersion[0] <= 0) { | |
176 | log_err("Properties doesn't reinitialize without u_init.\n"); | |
177 | } | |
374ca955 A |
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); | |
46f4442e A |
192 | |
193 | ctest_resetICU(); | |
374ca955 A |
194 | } |
195 | ||
196 |