16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org******************************************************************************
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   Copyright (C) 2002-2012, International Business Machines
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   Corporation and others.  All Rights Reserved.
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org******************************************************************************
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org* File cmemory.c      ICU Heap allocation.
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     All ICU heap allocation, both for C and C++ new of ICU
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     class types, comes through these functions.
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     If you have a need to replace ICU allocation, this is the
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     place to do it.
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     Note that uprv_malloc(0) returns a non-NULL pointer, and
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                     that a subsequent free of that pointer value is a NOP.
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org******************************************************************************
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*/
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/uclean.h"
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "putilimp.h"
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <stdlib.h>
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* uprv_malloc(0) returns a pointer to this read-only data. */
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const int32_t zeroMem[] = {0, 0, 0, 0, 0, 0};
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* Function Pointers for user-supplied heap functions  */
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const void     *pContext;
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UMemAllocFn    *pAlloc;
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UMemReallocFn  *pRealloc;
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UMemFreeFn     *pFree;
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* Flag indicating whether any heap allocations have happened.
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   Used to prevent changing out the heap functions after allocations have been made */
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UBool   gHeapInUse;
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <stdio.h>
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic int n=0;
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic long b=0;
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if U_DEBUG
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic char gValidMemorySink = 0;
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void uprv_checkValidMemory(const void *p, size_t n) {
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /*
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * Access the memory to ensure that it's all valid.
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * Load and save a computed value to try to ensure that the compiler
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * does not throw away the whole loop.
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * A thread analyzer might complain about un-mutexed access to gValidMemorySink
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     * which is true but harmless because no one ever uses the value in gValidMemorySink.
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org     */
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const char *s = (const char *)p;
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    char c = gValidMemorySink;
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    size_t i;
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(p != NULL);
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for(i = 0; i < n; ++i) {
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        c ^= s[i];
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    gValidMemorySink = c;
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif  /* U_DEBUG */
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void * U_EXPORT2
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orguprv_malloc(size_t s) {
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if 1
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  putchar('>');
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  fflush(stdout);
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#else
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  fprintf(stderr,"MALLOC\t#%d\t%ul bytes\t%ul total\n", ++n,s,(b+=s)); fflush(stderr);
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (s > 0) {
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        gHeapInUse = TRUE;
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (pAlloc) {
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return (*pAlloc)(pContext, s);
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return uprv_default_malloc(s);
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return (void *)zeroMem;
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void * U_EXPORT2
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orguprv_realloc(void * buffer, size_t size) {
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  putchar('~');
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  fflush(stdout);
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (buffer == zeroMem) {
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return uprv_malloc(size);
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else if (size == 0) {
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (pFree) {
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            (*pFree)(pContext, buffer);
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uprv_default_free(buffer);
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return (void *)zeroMem;
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        gHeapInUse = TRUE;
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (pRealloc) {
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return (*pRealloc)(pContext, buffer, size);
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return uprv_default_realloc(buffer, size);
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void U_EXPORT2
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orguprv_free(void *buffer) {
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  putchar('<');
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  fflush(stdout);
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (buffer != zeroMem) {
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (pFree) {
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            (*pFree)(pContext, buffer);
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uprv_default_free(buffer);
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void * U_EXPORT2
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orguprv_calloc(size_t num, size_t size) {
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    void *mem = NULL;
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    size *= num;
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    mem = uprv_malloc(size);
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (mem) {
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uprv_memset(mem, 0, size);
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return mem;
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CAPI void U_EXPORT2
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgu_setMemoryFunctions(const void *context, UMemAllocFn *a, UMemReallocFn *r, UMemFreeFn *f,  UErrorCode *status)
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(*status)) {
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (a==NULL || r==NULL || f==NULL) {
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        *status = U_ILLEGAL_ARGUMENT_ERROR;
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (gHeapInUse) {
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        *status = U_INVALID_STATE_ERROR;
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pContext  = context;
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pAlloc    = a;
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pRealloc  = r;
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pFree     = f;
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CFUNC UBool cmemory_cleanup(void) {
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pContext   = NULL;
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pAlloc     = NULL;
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pRealloc   = NULL;
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    pFree      = NULL;
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    gHeapInUse = FALSE;
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   gHeapInUse
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *       Return True if ICU has allocated any memory.
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *       Used by u_SetMutexFunctions() and similar to verify that ICU has not
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *               been used, that it is in a pristine initial state.
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CFUNC UBool cmemory_inUse() {
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return gHeapInUse;
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
184