1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 2003-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
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"
19 #include "unicode/utrace.h"
24 * This should align the memory properly on any machine.
30 } ctest_AlignedMemory
;
32 static void TestHeapFunctions(void);
34 void addHeapMutexTest(TestNode
**root
);
38 addHeapMutexTest(TestNode
** root
)
40 addTest(root
, &TestHeapFunctions
, "hpmufn/TestHeapFunctions" );
43 static int32_t gMutexFailures
= 0;
45 #define TEST_STATUS(status, expected) UPRV_BLOCK_MACRO_BEGIN { \
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++; \
50 } UPRV_BLOCK_MACRO_END
53 #define TEST_ASSERT(expr) UPRV_BLOCK_MACRO_BEGIN { \
55 log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \
58 } UPRV_BLOCK_MACRO_END
61 /* These tests do cleanup and reinitialize ICU in the course of their operation.
62 * The ICU data directory must be preserved across these operations.
63 * Here is a helper function to assist with that.
65 static char *safeGetICUDataDirectory() {
66 const char *dataDir
= u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
68 if (dataDir
!= NULL
) {
69 retStr
= (char *)malloc(strlen(dataDir
)+1);
70 strcpy(retStr
, dataDir
);
78 * Test Heap Functions.
79 * Implemented on top of the standard malloc heap.
80 * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
81 * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
82 * ends up being freed directly, without coming through us.
83 * Allocations are counted, to check that ICU actually does call back to us.
88 static void * U_CALLCONV
myMemAlloc(const void *context
, size_t size
) {
89 (void)context
; // suppress compiler warnings about unused variable
90 char *retPtr
= (char *)malloc(size
+sizeof(ctest_AlignedMemory
));
92 retPtr
+= sizeof(ctest_AlignedMemory
);
98 static void U_CALLCONV
myMemFree(const void *context
, void *mem
) {
99 (void)context
; // suppress compiler warnings about unused variable
100 char *freePtr
= (char *)mem
;
101 if (freePtr
!= NULL
) {
102 freePtr
-= sizeof(ctest_AlignedMemory
);
109 static void * U_CALLCONV
myMemRealloc(const void *context
, void *mem
, size_t size
) {
110 (void)context
; // suppress compiler warnings about unused variable
111 char *p
= (char *)mem
;
115 p
-= sizeof(ctest_AlignedMemory
);
117 retPtr
= realloc(p
, size
+sizeof(ctest_AlignedMemory
));
118 if (retPtr
!= NULL
) {
119 p
+= sizeof(ctest_AlignedMemory
);
125 static void TestHeapFunctions() {
126 UErrorCode status
= U_ZERO_ERROR
;
127 UResourceBundle
*rb
= NULL
;
129 UVersionInfo unicodeVersion
= {0,0,0,0};
131 icuDataDir
= safeGetICUDataDirectory(); /* save icu data dir, so we can put it back
132 * after doing u_cleanup(). */
135 /* Verify that ICU can be cleaned up and reinitialized successfully.
136 * Failure here usually means that some ICU service didn't clean up successfully,
137 * probably because some earlier test accidently left something open. */
140 /* Un-initialize ICU */
143 /* Can not set memory functions with NULL values */
144 status
= U_ZERO_ERROR
;
145 u_setMemoryFunctions(&gContext
, NULL
, myMemRealloc
, myMemFree
, &status
);
146 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
147 status
= U_ZERO_ERROR
;
148 u_setMemoryFunctions(&gContext
, myMemAlloc
, NULL
, myMemFree
, &status
);
149 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
150 status
= U_ZERO_ERROR
;
151 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, NULL
, &status
);
152 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
154 /* u_setMemoryFunctions() should work with null or non-null context pointer */
155 status
= U_ZERO_ERROR
;
156 u_setMemoryFunctions(NULL
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
157 TEST_STATUS(status
, U_ZERO_ERROR
);
158 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
159 TEST_STATUS(status
, U_ZERO_ERROR
);
162 /* After reinitializing ICU, we can not set the memory funcs again. */
163 status
= U_ZERO_ERROR
;
164 u_setDataDirectory(icuDataDir
);
166 TEST_STATUS(status
, U_ZERO_ERROR
);
168 /* Doing ICU operations should cause allocations to come through our test heap */
170 status
= U_ZERO_ERROR
;
171 rb
= ures_open(NULL
, "es", &status
);
172 TEST_STATUS(status
, U_ZERO_ERROR
);
173 if (gBlockCount
== 0) {
174 log_err("Heap functions are not being called from ICU.\n");
178 /* Cleanup should put the heap back to its default implementation. */
180 u_getUnicodeVersion(unicodeVersion
);
181 if (unicodeVersion
[0] <= 0) {
182 log_err("Properties doesn't reinitialize without u_init.\n");
184 status
= U_ZERO_ERROR
;
186 TEST_STATUS(status
, U_ZERO_ERROR
);
188 /* ICU operations should no longer cause allocations to come through our test heap */
190 status
= U_ZERO_ERROR
;
191 rb
= ures_open(NULL
, "fr", &status
);
192 TEST_STATUS(status
, U_ZERO_ERROR
);
193 if (gBlockCount
!= 0) {
194 log_err("Heap functions did not reset after u_cleanup.\n");