ICU-7947 UVector safety checks to avoid heap overflow due to integer overflow/signedness/truncation

X-SVN-Rev: 28626
This commit is contained in:
Michael Grady 2010-09-16 00:30:26 +00:00
parent 755b0f2a56
commit 290cadf0b8
5 changed files with 76 additions and 21 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);