From: Andy Heninger Date: Fri, 7 Sep 2018 20:42:21 +0000 (-0700) Subject: ICU-13834 add pinCapacity() for safer output buffer capacity checking. (#105) X-Git-Tag: release-63-rc~83 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=71c66bbb0bc4e17f179345692d0a32df1fcb3a83;p=icu ICU-13834 add pinCapacity() for safer output buffer capacity checking. (#105) * ICU-13834 add pinCapacity() for safer output buffer capacity checking. * ICU-13834 pinCapacity, fix typo in comment. --- diff --git a/icu4c/source/common/putilimp.h b/icu4c/source/common/putilimp.h index c43302d16c4..44f5bf34429 100644 --- a/icu4c/source/common/putilimp.h +++ b/icu4c/source/common/putilimp.h @@ -574,6 +574,49 @@ U_INTERNAL void * U_EXPORT2 uprv_maximumPtr(void *base); # endif #endif + +#ifdef __cplusplus +/** + * Pin a buffer capacity such that doing pointer arithmetic + * on the destination pointer and capacity cannot overflow. + * + * The pinned capacity must fulfill the following conditions (for positive capacities): + * - dest + capacity is a valid pointer according to the machine arcitecture (AS/400, 64-bit, etc.) + * - (dest + capacity) >= dest + * - The size (in bytes) of T[capacity] does not exceed 0x7fffffff + * + * @param dest the destination buffer pointer. + * @param capacity the requested buffer capacity, in units of type T. + * @return the pinned capacity. + * @internal + */ +template +inline int32_t pinCapacity(T *dest, int32_t capacity) { + if (capacity <= 0) { return capacity; } + + uintptr_t destInt = (uintptr_t)dest; + uintptr_t maxInt; + +# if U_PLATFORM == U_PF_OS390 && !defined(_LP64) + // We have 31-bit pointers. + maxInt = 0x7fffffff; +# elif U_PLATFORM == U_PF_OS400 + maxInt = (uintptr_t)uprv_maximumPtr((void *)dest); +# else + maxInt = destInt + 0x7fffffffu; + if (maxInt < destInt) { + // Less than 2GB to the end of the address space. + // Pin to that to prevent address overflow. + maxInt = (uintptr_t)-1; + } +# endif + + uintptr_t maxBytes = maxInt - destInt; // max. 2GB + int32_t maxCapacity = (int32_t)(maxBytes / sizeof(T)); + return capacity <= maxCapacity ? capacity : maxCapacity; +} +#endif // __cplusplus + /* Dynamic Library Functions */ typedef void (UVoidFunction)(void); diff --git a/icu4c/source/common/ucnv.cpp b/icu4c/source/common/ucnv.cpp index ae3c63d31a4..4e57619f500 100644 --- a/icu4c/source/common/ucnv.cpp +++ b/icu4c/source/common/ucnv.cpp @@ -1743,13 +1743,9 @@ ucnv_fromUChars(UConverter *cnv, } if(srcLength>0) { srcLimit=src+srcLength; + destCapacity=pinCapacity(dest, destCapacity); destLimit=dest+destCapacity; - /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */ - if(destLimit0) { srcLimit=src+srcLength; + destCapacity=pinCapacity(dest, destCapacity); destLimit=dest+destCapacity; - /* pin the destination limit to U_MAX_PTR; NULL check is for OS/400 */ - if(destLimit