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