]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/uvectr32.cpp
ICU-64243.0.1.tar.gz
[apple/icu.git] / icuSources / common / uvectr32.cpp
index fcf5c9a74a3191aae7247698be95e974a32dcee0..d1ae6599585086c5ac8d20cb0a6216d495756c4a 100644 (file)
@@ -1,7 +1,9 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 ******************************************************************************
-* Copyright (C) 1999-2003, International Business Machines Corporation and   *
-* others. All Rights Reserved.                                               *
+* Copyright (C) 1999-2015, International Business Machines Corporation and
+* others. All Rights Reserved.
 ******************************************************************************
 *   Date        Name        Description
 *   10/22/99    alan        Creation.
 
 #include "uvectr32.h"
 #include "cmemory.h"
+#include "putilimp.h"
 
 U_NAMESPACE_BEGIN
 
-#define DEFUALT_CAPACITY 8
+#define DEFAULT_CAPACITY 8
 
 /*
  * Constants for hinting whether a key is an integer
@@ -21,19 +24,21 @@ U_NAMESPACE_BEGIN
  * token is assumed to be an integer. This is needed for iSeries
  */
  
-const char UVector32::fgClassID=0;
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UVector32)
 
 UVector32::UVector32(UErrorCode &status) :
     count(0),
     capacity(0),
+    maxCapacity(0),
     elements(NULL)
 {
-    _init(DEFUALT_CAPACITY, status);
+    _init(DEFAULT_CAPACITY, status);
 }
 
 UVector32::UVector32(int32_t initialCapacity, UErrorCode &status) :
     count(0),
     capacity(0),
+    maxCapacity(0),
     elements(0)
 {
     _init(initialCapacity, status);
@@ -44,7 +49,13 @@ UVector32::UVector32(int32_t initialCapacity, UErrorCode &status) :
 void UVector32::_init(int32_t initialCapacity, UErrorCode &status) {
     // Fix bogus initialCapacity values; avoid malloc(0)
     if (initialCapacity < 1) {
-        initialCapacity = DEFUALT_CAPACITY;
+        initialCapacity = DEFAULT_CAPACITY;
+    }
+    if (maxCapacity>0 && maxCapacity<initialCapacity) {
+        initialCapacity = maxCapacity;
+    }
+    if (initialCapacity > (int32_t)(INT32_MAX / sizeof(int32_t))) {
+        initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
     }
     elements = (int32_t *)uprv_malloc(sizeof(int32_t)*initialCapacity);
     if (elements == 0) {
@@ -187,23 +198,74 @@ int32_t UVector32::indexOf(int32_t key, int32_t startIndex) const {
 
 
 UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    if (minimumCapacity < 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
     if (capacity >= minimumCapacity) {
         return TRUE;
-    } else {
-        int32_t newCap = capacity * 2;
-        if (newCap < minimumCapacity) {
-            newCap = minimumCapacity;
-        }
-        int32_t* newElems = (int32_t *)uprv_malloc(sizeof(int32_t)*newCap);
-        if (newElems == 0) {
-            status = U_MEMORY_ALLOCATION_ERROR;
-            return FALSE;
-        }
-        uprv_memcpy(newElems, elements, sizeof(elements[0]) * count);
-        uprv_free(elements);
-        elements = newElems;
-        capacity = newCap;
-        return TRUE;
+    }
+    if (maxCapacity>0 && minimumCapacity>maxCapacity) {
+        status = U_BUFFER_OVERFLOW_ERROR;
+        return FALSE;
+    }
+    if (capacity > (INT32_MAX - 1) / 2) {  // integer overflow check
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int32_t newCap = capacity * 2;
+    if (newCap < minimumCapacity) {
+        newCap = minimumCapacity;
+    }
+    if (maxCapacity > 0 && newCap > maxCapacity) {
+        newCap = maxCapacity;
+    }
+    if (newCap > (int32_t)(INT32_MAX / sizeof(int32_t))) {  // integer overflow check
+        // We keep the original memory contents on bad minimumCapacity/maxCapacity.
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    int32_t* newElems = (int32_t *)uprv_realloc(elements, sizeof(int32_t)*newCap);
+    if (newElems == NULL) {
+        // We keep the original contents on the memory failure on realloc.
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return FALSE;
+    }
+    elements = newElems;
+    capacity = newCap;
+    return TRUE;
+}
+
+void UVector32::setMaxCapacity(int32_t limit) {
+    U_ASSERT(limit >= 0);
+    if (limit < 0) {
+        limit = 0;
+    }
+    if (limit > (int32_t)(INT32_MAX / sizeof(int32_t))) {  // integer overflow check for realloc
+        //  Something is very wrong, don't realloc, leave capacity and maxCapacity unchanged
+        return;
+    }
+    maxCapacity = limit;
+    if (capacity <= maxCapacity || maxCapacity == 0) {
+        // Current capacity is within the new limit.
+        return;
+    }
+    
+    // New maximum capacity is smaller than the current size.
+    // Realloc the storage to the new, smaller size.
+    int32_t* newElems = (int32_t *)uprv_realloc(elements, sizeof(int32_t)*maxCapacity);
+    if (newElems == NULL) {
+        // Realloc to smaller failed.
+        //   Just keep what we had.  No need to call it a failure.
+        return;
+    }
+    elements = newElems;
+    capacity = maxCapacity;
+    if (count > capacity) {
+        count = capacity;
     }
 }