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 */ 24typedef union { 25 long t1; 26 double t2; 27 void *t3; 28} ctest_AlignedMemory; 29 30static void TestHeapFunctions(void); 31 32void addHeapMutexTest(TestNode **root); 33 34 35void 36addHeapMutexTest(TestNode** root) 37{ 38 addTest(root, &TestHeapFunctions, "hpmufn/TestHeapFunctions" ); 39} 40 41static int32_t gMutexFailures = 0; 42 43#define TEST_STATUS(status, expected) \ 44if (status != expected) { \ 45log_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) \ 50if (!(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 */ 60static 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 */ 80int gBlockCount = 0; 81const void *gContext; 82 83static 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 92static 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 102static 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 117static 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