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