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
addHeapMutexTest(TestNode ** root)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  */
safeGetICUDataDirectory()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 
myMemAlloc(const void * context,size_t size)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 
myMemFree(const void * context,void * mem)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 
myMemRealloc(const void * context,void * mem,size_t size)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 
TestHeapFunctions()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     /* 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 heap */
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 test 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 
195