mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 17:01:16 +00:00
ICU-7947 UVector safety checks to avoid heap overflow due to integer overflow/signedness/truncation
X-SVN-Rev: 28626
This commit is contained in:
parent
755b0f2a56
commit
290cadf0b8
5 changed files with 76 additions and 21 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 1999-2009, International Business Machines Corporation and *
|
||||
* Copyright (C) 1999-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
******************************************************************************
|
||||
* Date Name Description
|
||||
|
@ -14,7 +14,7 @@
|
|||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
#define DEFUALT_CAPACITY 8
|
||||
#define DEFAULT_CAPACITY 8
|
||||
|
||||
/*
|
||||
* Constants for hinting whether a key is an integer
|
||||
|
@ -33,7 +33,7 @@ UVector::UVector(UErrorCode &status) :
|
|||
deleter(0),
|
||||
comparer(0)
|
||||
{
|
||||
_init(DEFUALT_CAPACITY, status);
|
||||
_init(DEFAULT_CAPACITY, status);
|
||||
}
|
||||
|
||||
UVector::UVector(int32_t initialCapacity, UErrorCode &status) :
|
||||
|
@ -53,7 +53,7 @@ UVector::UVector(UObjectDeleter *d, UKeyComparator *c, UErrorCode &status) :
|
|||
deleter(d),
|
||||
comparer(c)
|
||||
{
|
||||
_init(DEFUALT_CAPACITY, status);
|
||||
_init(DEFAULT_CAPACITY, status);
|
||||
}
|
||||
|
||||
UVector::UVector(UObjectDeleter *d, UKeyComparator *c, int32_t initialCapacity, UErrorCode &status) :
|
||||
|
@ -70,9 +70,9 @@ void UVector::_init(int32_t initialCapacity, UErrorCode &status) {
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
// Fix bogus initialCapacity values; avoid malloc(0)
|
||||
if (initialCapacity < 1) {
|
||||
initialCapacity = DEFUALT_CAPACITY;
|
||||
// Fix bogus initialCapacity values; avoid malloc(0) and integer overflow
|
||||
if ((initialCapacity < 1) || (initialCapacity > INT32_MAX / sizeof(UHashTok))) {
|
||||
initialCapacity = DEFAULT_CAPACITY;
|
||||
}
|
||||
elements = (UHashTok *)uprv_malloc(sizeof(UHashTok)*initialCapacity);
|
||||
if (elements == 0) {
|
||||
|
@ -326,14 +326,27 @@ int32_t UVector::indexOf(UHashTok key, int32_t startIndex, int8_t hint) const {
|
|||
}
|
||||
|
||||
UBool UVector::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
||||
if (minimumCapacity < 1) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
if (capacity < minimumCapacity) {
|
||||
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 (newCap > INT32_MAX / sizeof(UHashTok)) { // integer overflow check
|
||||
// We keep the original memory contents on bad minimumCapacity.
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
UHashTok* newElems = (UHashTok *)uprv_realloc(elements, sizeof(UHashTok)*newCap);
|
||||
if (newElems == NULL) {
|
||||
// We keep the original contents on the memory failure on realloc.
|
||||
// We keep the original contents on the memory failure on realloc or bad minimumCapacity.
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
******************************************************************************
|
||||
* Copyright (C) 1999-2008, International Business Machines Corporation and *
|
||||
* Copyright (C) 1999-2010, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
******************************************************************************
|
||||
* Date Name Description
|
||||
|
@ -10,10 +10,11 @@
|
|||
|
||||
#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
|
||||
|
@ -29,7 +30,7 @@ UVector32::UVector32(UErrorCode &status) :
|
|||
maxCapacity(0),
|
||||
elements(NULL)
|
||||
{
|
||||
_init(DEFUALT_CAPACITY, status);
|
||||
_init(DEFAULT_CAPACITY, status);
|
||||
}
|
||||
|
||||
UVector32::UVector32(int32_t initialCapacity, UErrorCode &status) :
|
||||
|
@ -46,11 +47,14 @@ 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_MAX / sizeof(int32_t)) {
|
||||
initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
|
||||
}
|
||||
elements = (int32_t *)uprv_malloc(sizeof(int32_t)*initialCapacity);
|
||||
if (elements == 0) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
|
@ -192,6 +196,10 @@ int32_t UVector32::indexOf(int32_t key, int32_t startIndex) const {
|
|||
|
||||
|
||||
UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
||||
if (minimumCapacity < 1) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
if (capacity >= minimumCapacity) {
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -199,6 +207,10 @@ UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
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;
|
||||
|
@ -206,6 +218,11 @@ UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
if (maxCapacity > 0 && newCap > maxCapacity) {
|
||||
newCap = maxCapacity;
|
||||
}
|
||||
if (newCap > 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.
|
||||
|
@ -219,10 +236,14 @@ UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
|
||||
void UVector32::setMaxCapacity(int32_t limit) {
|
||||
U_ASSERT(limit >= 0);
|
||||
maxCapacity = limit;
|
||||
if (maxCapacity < 0) {
|
||||
maxCapacity = 0;
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
if (limit > 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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) 1999-2008, International Business Machines
|
||||
* Copyright (C) 1999-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*/
|
||||
|
@ -211,7 +211,7 @@ public:
|
|||
// UVector32 inlines
|
||||
|
||||
inline UBool UVector32::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
||||
if (capacity >= minimumCapacity) {
|
||||
if ((minimumCapacity > 0) && (capacity >= minimumCapacity)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return expandCapacity(minimumCapacity, status);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "uvectr64.h"
|
||||
#include "cmemory.h"
|
||||
#include "putilimp.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -48,6 +49,9 @@ void UVector64::_init(int32_t initialCapacity, UErrorCode &status) {
|
|||
if (maxCapacity>0 && maxCapacity<initialCapacity) {
|
||||
initialCapacity = maxCapacity;
|
||||
}
|
||||
if (initialCapacity > INT32_MAX / sizeof(int64_t)) {
|
||||
initialCapacity = uprv_min(DEFAULT_CAPACITY, maxCapacity);
|
||||
}
|
||||
elements = (int64_t *)uprv_malloc(sizeof(int64_t)*initialCapacity);
|
||||
if (elements == 0) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
|
@ -110,6 +114,10 @@ void UVector64::removeAllElements(void) {
|
|||
}
|
||||
|
||||
UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
||||
if (minimumCapacity < 1) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
if (capacity >= minimumCapacity) {
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -117,6 +125,10 @@ UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
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;
|
||||
|
@ -124,6 +136,11 @@ UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
if (maxCapacity > 0 && newCap > maxCapacity) {
|
||||
newCap = maxCapacity;
|
||||
}
|
||||
if (newCap > INT32_MAX / sizeof(int64_t)) { // integer overflow check
|
||||
// We keep the original memory contents on bad minimumCapacity/maxCapacity.
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return FALSE;
|
||||
}
|
||||
int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap);
|
||||
if (newElems == NULL) {
|
||||
// We keep the original contents on the memory failure on realloc.
|
||||
|
@ -137,10 +154,14 @@ UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
|||
|
||||
void UVector64::setMaxCapacity(int32_t limit) {
|
||||
U_ASSERT(limit >= 0);
|
||||
maxCapacity = limit;
|
||||
if (maxCapacity < 0) {
|
||||
maxCapacity = 0;
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
if (limit > INT32_MAX / sizeof(int64_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;
|
||||
|
|
|
@ -200,7 +200,7 @@ public:
|
|||
// UVector64 inlines
|
||||
|
||||
inline UBool UVector64::ensureCapacity(int32_t minimumCapacity, UErrorCode &status) {
|
||||
if (capacity >= minimumCapacity) {
|
||||
if ((minimumCapacity > 0) && (capacity >= minimumCapacity)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return expandCapacity(minimumCapacity, status);
|
||||
|
|
Loading…
Add table
Reference in a new issue