1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/********************************************************************
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * COPYRIGHT:
359d709d503bab6e2b61931737e662dd293b40578ccornelius * Copyright (c) 2003-2013, International Business Machines Corporation and
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * others. All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru ********************************************************************/
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* File hpmufn.c
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/putil.h"
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uclean.h"
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uchar.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ures.h"
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cintltst.h"
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utrace.h"
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <stdlib.h>
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <string.h>
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This should align the memory properly on any machine.
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef union {
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    long    t1;
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double  t2;
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    void   *t3;
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} ctest_AlignedMemory;
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void TestHeapFunctions(void);
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid addHeapMutexTest(TestNode **root);
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruaddHeapMutexTest(TestNode** root)
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    addTest(root, &TestHeapFunctions,       "hpmufn/TestHeapFunctions"  );
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t gMutexFailures = 0;
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define TEST_STATUS(status, expected) \
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruif (status != expected) { \
456d5deb12725f146643d443090dfa11b206df528aJean-Baptiste Querulog_err_status(status, "FAIL at  %s:%d. Actual status = \"%s\";  Expected status = \"%s\"\n", \
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; }
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define TEST_ASSERT(expr) \
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruif (!(expr)) { \
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    log_err("FAILED Assertion \"" #expr "\" at  %s:%d.\n", __FILE__, __LINE__); \
52b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    gMutexFailures++; \
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  These tests do cleanup and reinitialize ICU in the course of their operation.
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *    The ICU data directory must be preserved across these operations.
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *    Here is a helper function to assist with that.
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic char *safeGetICUDataDirectory() {
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *dataDir = u_getDataDirectory();  /* Returned string vanashes with u_cleanup */
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *retStr = NULL;
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (dataDir != NULL) {
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        retStr = (char *)malloc(strlen(dataDir)+1);
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        strcpy(retStr, dataDir);
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return retStr;
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *  Test Heap Functions.
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *    Implemented on top of the standard malloc heap.
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *    All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *       offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *       ends up being freed directly, without coming through us.
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *    Allocations are counted, to check that ICU actually does call back to us.
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint    gBlockCount = 0;
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruconst void  *gContext;
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void * U_CALLCONV myMemAlloc(const void *context, size_t size) {
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *retPtr = (char *)malloc(size+sizeof(ctest_AlignedMemory));
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (retPtr != NULL) {
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        retPtr += sizeof(ctest_AlignedMemory);
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    gBlockCount ++;
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return retPtr;
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV myMemFree(const void *context, void *mem) {
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *freePtr = (char *)mem;
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (freePtr != NULL) {
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        freePtr -= sizeof(ctest_AlignedMemory);
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    free(freePtr);
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
99b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void * U_CALLCONV myMemRealloc(const void *context, void *mem, size_t size) {
103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *p = (char *)mem;
104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *retPtr;
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
106b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (p!=NULL) {
107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        p -= sizeof(ctest_AlignedMemory);
108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    retPtr = realloc(p, size+sizeof(ctest_AlignedMemory));
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (retPtr != NULL) {
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        p += sizeof(ctest_AlignedMemory);
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return retPtr;
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void TestHeapFunctions() {
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode       status = U_ZERO_ERROR;
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UResourceBundle *rb     = NULL;
120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char            *icuDataDir;
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UVersionInfo unicodeVersion = {0,0,0,0};
122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    icuDataDir = safeGetICUDataDirectory();   /* save icu data dir, so we can put it back
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                               *  after doing u_cleanup().                */
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Verify that ICU can be cleaned up and reinitialized successfully.
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     *  Failure here usually means that some ICU service didn't clean up successfully,
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     *  probably because some earlier test accidently left something open. */
130c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    ctest_resetICU();
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Can not set memory functions if ICU is already initialized */
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_INVALID_STATE_ERROR);
135b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Un-initialize ICU */
137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_cleanup();
138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Can not set memory functions with NULL values */
140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status);
142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status);
145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status);
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* u_setMemoryFunctions() should work with null or non-null context pointer */
151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
155b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* After reinitializing ICU, we should not be able to set the memory funcs again. */
159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setDataDirectory(icuDataDir);
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_init(&status);
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_INVALID_STATE_ERROR);
165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
166b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Doing ICU operations should cause allocations to come through our test heap */
167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    gBlockCount = 0;
168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    rb = ures_open(NULL, "es", &status);
170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
171b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (gBlockCount == 0) {
172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Heap functions are not being called from ICU.\n");
173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ures_close(rb);
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Cleanup should put the heap back to its default implementation. */
177c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    ctest_resetICU();
178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_getUnicodeVersion(unicodeVersion);
179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (unicodeVersion[0] <= 0) {
180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Properties doesn't reinitialize without u_init.\n");
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    u_init(&status);
184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* ICU operations should no longer cause allocations to come through our test heap */
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    gBlockCount = 0;
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    status = U_ZERO_ERROR;
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    rb = ures_open(NULL, "fr", &status);
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    TEST_STATUS(status, U_ZERO_ERROR);
191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (gBlockCount != 0) {
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        log_err("Heap functions did not reset after u_cleanup.\n");
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ures_close(rb);
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    free(icuDataDir);
196c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
197c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    ctest_resetICU();
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
201