Home | History | Annotate | Download | only in cintltst
      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
     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 
    197