Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / cintltst / hpmufn.c
1 // Copyright (C) 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
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  */
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
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
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
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
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