Home | History | Annotate | Download | only in cintltst
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 2003-2013, 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     /* Can not set memory functions if ICU is already initialized */
    133     u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
    134     TEST_STATUS(status, U_INVALID_STATE_ERROR);
    135 
    136     /* Un-initialize ICU */
    137     u_cleanup();
    138 
    139     /* Can not set memory functions with NULL values */
    140     status = U_ZERO_ERROR;
    141     u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status);
    142     TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
    143     status = U_ZERO_ERROR;
    144     u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status);
    145     TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
    146     status = U_ZERO_ERROR;
    147     u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status);
    148     TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
    149 
    150     /* u_setMemoryFunctions() should work with null or non-null context pointer */
    151     status = U_ZERO_ERROR;
    152     u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
    153     TEST_STATUS(status, U_ZERO_ERROR);
    154     u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
    155     TEST_STATUS(status, U_ZERO_ERROR);
    156 
    157 
    158     /* After reinitializing ICU, we should not be able to set the memory funcs again. */
    159     status = U_ZERO_ERROR;
    160     u_setDataDirectory(icuDataDir);
    161     u_init(&status);
    162     TEST_STATUS(status, U_ZERO_ERROR);
    163     u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
    164     TEST_STATUS(status, U_INVALID_STATE_ERROR);
    165 
    166     /* Doing ICU operations should cause allocations to come through our test heap */
    167     gBlockCount = 0;
    168     status = U_ZERO_ERROR;
    169     rb = ures_open(NULL, "es", &status);
    170     TEST_STATUS(status, U_ZERO_ERROR);
    171     if (gBlockCount == 0) {
    172         log_err("Heap functions are not being called from ICU.\n");
    173     }
    174     ures_close(rb);
    175 
    176     /* Cleanup should put the heap back to its default implementation. */
    177     ctest_resetICU();
    178     u_getUnicodeVersion(unicodeVersion);
    179     if (unicodeVersion[0] <= 0) {
    180         log_err("Properties doesn't reinitialize without u_init.\n");
    181     }
    182     status = U_ZERO_ERROR;
    183     u_init(&status);
    184     TEST_STATUS(status, U_ZERO_ERROR);
    185 
    186     /* ICU operations should no longer cause allocations to come through our test heap */
    187     gBlockCount = 0;
    188     status = U_ZERO_ERROR;
    189     rb = ures_open(NULL, "fr", &status);
    190     TEST_STATUS(status, U_ZERO_ERROR);
    191     if (gBlockCount != 0) {
    192         log_err("Heap functions did not reset after u_cleanup.\n");
    193     }
    194     ures_close(rb);
    195     free(icuDataDir);
    196 
    197     ctest_resetICU();
    198 }
    199 
    200 
    201