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 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 */ 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 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 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 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