Chrome · V8 › Icu
CVE-2026-118318
Logic Error in V8 (Icu)
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifpatches/charstr.patch |
modified | |
ifsource/common/charstr.cpp |
modified |
Files Changed
source/common/charstr.cpppatches/charstr.patchsource/test/intltest/strtest.cppREADME.chromium
Patch
From 83ffaeb85f98281e897f022d4ddc73ccd3cc1fb3 Mon Sep 17 00:00:00 2001
From: Olivier Flückiger <olivf@chromium.org>
Date: Wed, 14 Oct 2026 10:31:32 +0000
Subject: [PATCH] [icu] Fix signed int32_t overflow in CharString
Cherry-pick upstream ICU commit d37a22cb9921a76268e325fdca7d3e70a6851191
(https://github.com/unicode-org/icu/pull/4243) to check for signed
32-bit integer overflow when computing new capacities in CharString.
Bug: 565133743
Change-Id: Ife31d8e8d01fda0e410b5cdeb4ccac1192c870c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/icu/+/8579140
Reviewed-by: Koji Ishii <kojii@chromium.org>
---
diff --git a/README.chromium b/README.chromium
index 4960cc3..a8ae5ea 100644
--- a/README.chromium
+++ b/README.chromium
@@ -270,3 +270,9 @@
13. Missing long name in iso8601 calendar.
https://unicode-org.atlassian.net/browse/ICU-23262
- patches/missing_iso8601_resource.patch
+
+14. Fix signed int32_t overflow in CharString.
+ - patches/charstr.patch
+ - https://unicode-org.atlassian.net/browse/ICU-23537
+ - https://github.com/unicode-org/icu/pull/4243
+ - https://crbug.com/565133743
diff --git a/patches/charstr.patch b/patches/charstr.patch
new file mode 100644
index 0000000..ebf713e
--- /dev/null
+++ b/patches/charstr.patch
@@ -0,0 +1,270 @@
+diff --git a/source/common/charstr.cpp b/source/common/charstr.cpp
+index dadc829b0..f956c419d 100644
+--- a/source/common/charstr.cpp
++++ b/source/common/charstr.cpp
+@@ -21,6 +21,7 @@
+ #include "charstr.h"
+ #include "cmemory.h"
+ #include "cstring.h"
++#include "putilimp.h"
+ #include "uinvchar.h"
+ #include "ustr_imp.h"
+
+@@ -111,7 +112,15 @@ CharString &CharString::truncate(int32_t newLength) {
+ }
+
+ CharString &CharString::append(char c, UErrorCode &errorCode) {
+- if(ensureCapacity(len+2, 0, errorCode)) {
++ if(U_FAILURE(errorCode)) {
++ return *this;
++ }
++ int32_t newCapacity;
++ if (uprv_add32_overflow(len, 2, &newCapacity)) {
++ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
++ return *this;
++ }
++ if(ensureCapacity(newCapacity, 0, errorCode)) {
+ buffer[len++]=c;
+ buffer[len]=0;
+ }
+@@ -138,15 +147,21 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
+ } else {
+ buffer[len+=sLength]=0;
+ }
+- } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
+- sLength>=(buffer.getCapacity()-len)
+- ) {
+- // (Part of) this string is appended to itself which requires reallocation,
+- // so we have to make a copy of the substring and append that.
+- return append(CharString(s, sLength, errorCode), errorCode);
+- } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
+- uprv_memcpy(buffer.getAlias()+len, s, sLength);
+- buffer[len+=sLength]=0;
++ } else {
++ int32_t newCapacity;
++ if(uprv_add32_overflow(len, sLength, &newCapacity) ||
++ uprv_add32_overflow(newCapacity, 1, &newCapacity)) {
++ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
++ } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
++ newCapacity>buffer.getCapacity()
++ ) {
++ // (Part of) this string is appended to itself which requires reallocation,
++ // so we have to make a copy of the substring and append that.
++ return append(CharString(s, sLength, errorCode), errorCode);
++ } else if(ensureCapacity(newCapacity, 0, errorCode)) {
++ uprv_memcpy(buffer.getAlias()+len, s, sLength);
++ buffer[len+=sLength]=0;
++ }
+ }
+ }
+ return *this;
+@@ -192,12 +207,30 @@ char *CharString::getAppendBuffer(int32_t minCapacity,
+ resultCapacity=0;
+ return nullptr;
+ }
++ if(minCapacity<0 || desiredCapacityHint<0) {
++ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
++ resultCapacity=0;
++ return nullptr;
++ }
+ int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
+ if(appendCapacity>=minCapacity) {
+ resultCapacity=appendCapacity;
+ return buffer.getAlias()+len;
+ }
+- if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
++ int32_t newCapacity;
++ if(uprv_add32_overflow(len, minCapacity, &newCapacity) ||
++ uprv_add32_overflow(newCapacity, 1, &newCapacity)) {
++ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
++ resultCapacity=0;
++ return nullptr;
++ }
++ int32_t newDesiredCapacity = 0;
++ if(desiredCapacityHint > 0 &&
++ (uprv_add32_overflow(len, desiredCapacityHint, &newDesiredCapacity) ||
++ uprv_add32_overflow(newDesiredCapacity, 1, &newDesiredCapacity))) {
++ newDesiredCapacity = 0;
++ }
++ if(ensureCapacity(newCapacity, newDesiredCapacity, errorCode)) {
+ resultCapacity=buffer.getCapacity()-len-1;
+ return buffer.getAlias()+len;
+ }
+@@ -213,11 +246,21 @@ CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t uch
+ if(U_FAILURE(errorCode)) {
+ return *this;
+ }
++ if(ucharsLen < 0 || (uchars == nullptr && ucharsLen != 0)) {
++ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
++ return *this;
++ }
+ if (!uprv_isInvariantUString(uchars, ucharsLen)) {
+ errorCode = U_INVARIANT_CONVERSION_ERROR;
+ return *this;
+ }
+- if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
++ int32_t newCapacity;
++ if (uprv_add32_overflow(len, ucharsLen, &newCapacity) ||
++ uprv_add32_overflow(newCapacity, 1, &newCapacity)) {
++ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
++ return *this;
++ }
++ if(ensureCapacity(newCapacity, 0, errorCode)) {
+ u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
+ len += ucharsLen;
+ buffer[len] = 0;
+@@ -231,9 +274,17 @@ UBool CharString::ensureCapacity(int32_t capacity,
+ if(U_FAILURE(errorCode)) {
+ return false;
+ }
++ if(capacity<0) {
++ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
++ return false;
++ }
+ if(capacity>buffer.getCapacity()) {
+ if(desiredCapacityHint==0) {
+- desiredCapacityHint=capacity+buffer.getCapacity();
++ // Default growth heuristic. If it overflows, skip the extra headroom
++ // and allocate exactly the requested capacity, which is still valid.
++ if(uprv_add32_overflow(capacity, buffer.getCapacity(), &desiredCapacityHint)) {
++ desiredCapacityHint=0;
++ }
+ }
+ if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) &&
+ buffer.resize(capacity, len+1)==nullptr
+diff --git a/source/test/intltest/strtest.cpp b/source/test/intltest/strtest.cpp
+index bf63dfaec..ee0d7a11b 100644
+--- a/source/test/intltest/strtest.cpp
++++ b/source/test/intltest/strtest.cpp
+@@ -836,6 +836,131 @@ StringTest::TestCharString() {
+ s.extract(buffer, 2, errorCode);
+ assertEquals("abc.extract(2) overflow", U_BUFFER_OVERFLOW_ERROR, errorCode.reset());
+ }
++
++ {
++ errorCode.reset();
++ CharString s("abc", errorCode);
++ int32_t capacity = -1;
++
++ assertTrue("getAppendBuffer(minCapacity<0)",
++ s.getAppendBuffer(-1, 10, capacity, errorCode) == nullptr);
++ assertEquals("getAppendBuffer(minCapacity<0) error",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("getAppendBuffer(minCapacity<0) capacity", 0, capacity);
++
++ capacity = -1;
++ assertTrue("getAppendBuffer(desiredCapacityHint<0)",
++ s.getAppendBuffer(10, -1, capacity, errorCode) == nullptr);
++ assertEquals("getAppendBuffer(desiredCapacityHint<0) error",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("getAppendBuffer(desiredCapacityHint<0) capacity", 0, capacity);
++
++ capacity = -1;
++ assertTrue("getAppendBuffer(INT32_MAX)",
++ s.getAppendBuffer(INT32_MAX, 0, capacity, errorCode) == nullptr);
++ assertEquals("getAppendBuffer(INT32_MAX) error",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("getAppendBuffer(INT32_MAX) capacity", 0, capacity);
++
++ capacity = -1;
++ assertTrue("getAppendBuffer(INT32_MAX - len)",
++ s.getAppendBuffer(INT32_MAX - s.length(), 0, capacity, errorCode) == nullptr);
++ assertEquals("getAppendBuffer(INT32_MAX - len) error",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("getAppendBuffer(INT32_MAX - len) capacity", 0, capacity);
++
++ assertTrue("getAppendBuffer(hint=INT32_MAX)",
++ s.getAppendBuffer(50, INT32_MAX, capacity, errorCode) != nullptr);
++ assertEquals("getAppendBuffer(hint=INT32_MAX) success",
++ U_ZERO_ERROR, errorCode.reset());
++ assertTrue("getAppendBuffer(hint=INT32_MAX) capacity", capacity >= 50);
++
++ assertTrue("getAppendBuffer(hint=INT32_MAX - len)",
++ s.getAppendBuffer(150, INT32_MAX - s.length(), capacity, errorCode) != nullptr);
++ assertEquals("getAppendBuffer(hint=INT32_MAX - len) success",
++ U_ZERO_ERROR, errorCode.reset());
++ assertTrue("getAppendBuffer(hint=INT32_MAX - len) capacity", capacity >= 150);
++
++ s.appendInvariantChars(u"abc", -1, errorCode);
++ assertEquals("appendInvariantChars(ucharsLen<0)",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++
++ s.appendInvariantChars(nullptr, 1, errorCode);
++ assertEquals("appendInvariantChars(nullptr, 1)",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++
++ s.append("x", INT32_MAX, errorCode);
++ assertEquals("append(INT32_MAX)", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("append(INT32_MAX) length unchanged", 3, s.length());
++
++ s.append("x", INT32_MAX - s.length(), errorCode);
++ assertEquals("append(INT32_MAX - len)", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("append(INT32_MAX - len) length unchanged", 3, s.length());
++
++ constexpr int32_t kChunkLen = 0x30000000;
++ CharString chunk;
++ char* buf = chunk.getAppendBuffer(kChunkLen, kChunkLen, capacity, errorCode);
++ if (buf != nullptr && errorCode.isSuccess()) {
++ uprv_memset(buf, 'a', kChunkLen);
++ chunk.append(buf, kChunkLen, errorCode);
++ CharString dest;
++ int64_t total = 0;
++ for (int32_t i = 0; i < 3; ++i) {
++ int32_t prevLen = dest.length();
++ dest.append(chunk, errorCode);
++ total += kChunkLen;
++ if (total < INT32_MAX) {
++ if (errorCode.isFailure()) {
++ assertEquals("append allocation failure",
++ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
++ break;
++ }
++ assertEquals("dest.length()", static_cast<int32_t>(total), dest.length());
++ } else {
++ assertEquals("append overflow", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("dest.length() unchanged", prevLen, dest.length());
++ }
++ }
++ if (dest.length() == 2 * kChunkLen) {
++ int32_t remain = (INT32_MAX - 1) - dest.length();
++ dest.append(chunk.data(), remain, errorCode);
++ if (errorCode.isSuccess()) {
++ assertEquals("dest at max length", INT32_MAX - 1, dest.length());
++
++ dest.append('a', errorCode);
++ assertEquals("append(char) overflow",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("dest.length() after append(char)", INT32_MAX - 1, dest.length());
++
++ dest.append("a", 1, errorCode);
++ assertEquals("append(char*, 1) overflow",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("dest.length() after append(char*, 1)",
++ INT32_MAX - 1, dest.length());
++
++ dest.appendInvariantChars(u"a", 1, errorCode);
++ assertEquals("appendInvariantChars(1) overflow",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("dest.length() after appendInvariantChars(1)",
++ INT32_MAX - 1, dest.length());
++
++ dest.appendInvariantChars(u"ab", 2, errorCode);
++ assertEquals("appendInvariantChars(2) overflow",
++ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
++ assertEquals("dest.length() after appendInvariantChars(2)",
++ INT32_MAX - 1, dest.length());
++ } else {
++ assertEquals("append remain allocation failure",
++ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
++ }
++ }
++ } else {
++ // Allocating 768 MiB (kChunkLen) can legitimately fail on 32-bit
++ // platforms or memory-constrained test runners.
++ assertEquals("chunk allocation failure",
++ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
++ }
++ }
+ }
+
+ void
diff --git a/source/common/charstr.cpp b/source/common/charstr.cpp
index dadc829..f956c41 100644
--- a/source/common/charstr.cpp
+++ b/source/common/charstr.cpp
@@ -21,6 +21,7 @@
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
+#include "putilimp.h"
#include "uinvchar.h"
#include "ustr_imp.h"
@@ -111,7 +112,15 @@
}
CharString &CharString::append(char c, UErrorCode &errorCode) {
- if(ensureCapacity(len+2, 0, errorCode)) {
+ if(U_FAILURE(errorCode)) {
+ return *this;
+ }
+ int32_t newCapacity;
+ if (uprv_add32_overflow(len, 2, &newCapacity)) {
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ if(ensureCapacity(newCapacity, 0, errorCode)) {
buffer[len++]=c;
buffer[len]=0;
}
@@ -138,15 +147,21 @@
} else {
buffer[len+=sLength]=0;
}
- } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
- sLength>=(buffer.getCapacity()-len)
- ) {
- // (Part of) this string is appended to itself which requires reallocation,
- // so we have to make a copy of the substring and append that.
- return append(CharString(s, sLength, errorCode), errorCode);
- } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
- uprv_memcpy(buffer.getAlias()+len, s, sLength);
- buffer[len+=sLength]=0;
+ } else {
+ int32_t newCapacity;
+ if(uprv_add32_overflow(len, sLength, &newCapacity) ||
+ uprv_add32_overflow(newCapacity, 1, &newCapacity)) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
+ newCapacity>buffer.getCapacity()
+ ) {
+ // (Part of) this string is appended to itself which requires reallocation,
+ // so we have to make a copy of the substring and append that.
+ return append(CharString(s, sLength, errorCode), errorCode);
+ } else if(ensureCapacity(newCapacity, 0, errorCode)) {
+ uprv_memcpy(buffer.getAlias()+len, s, sLength);
+ buffer[len+=sLength]=0;
+ }
}
}
return *this;
@@ -192,12 +207,30 @@
resultCapacity=0;
return nullptr;
}
+ if(minCapacity<0 || desiredCapacityHint<0) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ resultCapacity=0;
+ return nullptr;
+ }
int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
if(appendCapacity>=minCapacity) {
resultCapacity=appendCapacity;
return buffer.getAlias()+len;
}
- if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
+ int32_t newCapacity;
+ if(uprv_add32_overflow(len, minCapacity, &newCapacity) ||
+ uprv_add32_overflow(newCapacity, 1, &newCapacity)) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ resultCapacity=0;
+ return nullptr;
+ }
+ int32_t newDesiredCapacity = 0;
+ if(desiredCapacityHint > 0 &&
+ (uprv_add32_overflow(len, desiredCapacityHint, &newDesiredCapacity) ||
+ uprv_add32_overflow(newDesiredCapacity, 1, &newDesiredCapacity))) {
+ newDesiredCapacity = 0;
+ }
+ if(ensureCapacity(newCapacity, newDesiredCapacity, errorCode)) {
resultCapacity=buffer.getCapacity()-len-1;
return buffer.getAlias()+len;
}
@@ -213,11 +246,21 @@
if(U_FAILURE(errorCode)) {
return *this;
}
... (file diff truncated)
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/source/test/intltest/strtest.cpp b/source/test/intltest/strtest.cpp
index bf63dfa..ee0d7a1 100644
--- a/source/test/intltest/strtest.cpp
+++ b/source/test/intltest/strtest.cpp
@@ -836,6 +836,131 @@
s.extract(buffer, 2, errorCode);
assertEquals("abc.extract(2) overflow", U_BUFFER_OVERFLOW_ERROR, errorCode.reset());
}
+
+ {
+ errorCode.reset();
+ CharString s("abc", errorCode);
+ int32_t capacity = -1;
+
+ assertTrue("getAppendBuffer(minCapacity<0)",
+ s.getAppendBuffer(-1, 10, capacity, errorCode) == nullptr);
+ assertEquals("getAppendBuffer(minCapacity<0) error",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("getAppendBuffer(minCapacity<0) capacity", 0, capacity);
+
+ capacity = -1;
+ assertTrue("getAppendBuffer(desiredCapacityHint<0)",
+ s.getAppendBuffer(10, -1, capacity, errorCode) == nullptr);
+ assertEquals("getAppendBuffer(desiredCapacityHint<0) error",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("getAppendBuffer(desiredCapacityHint<0) capacity", 0, capacity);
+
+ capacity = -1;
+ assertTrue("getAppendBuffer(INT32_MAX)",
+ s.getAppendBuffer(INT32_MAX, 0, capacity, errorCode) == nullptr);
+ assertEquals("getAppendBuffer(INT32_MAX) error",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("getAppendBuffer(INT32_MAX) capacity", 0, capacity);
+
+ capacity = -1;
+ assertTrue("getAppendBuffer(INT32_MAX - len)",
+ s.getAppendBuffer(INT32_MAX - s.length(), 0, capacity, errorCode) == nullptr);
+ assertEquals("getAppendBuffer(INT32_MAX - len) error",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("getAppendBuffer(INT32_MAX - len) capacity", 0, capacity);
+
+ assertTrue("getAppendBuffer(hint=INT32_MAX)",
+ s.getAppendBuffer(50, INT32_MAX, capacity, errorCode) != nullptr);
+ assertEquals("getAppendBuffer(hint=INT32_MAX) success",
+ U_ZERO_ERROR, errorCode.reset());
+ assertTrue("getAppendBuffer(hint=INT32_MAX) capacity", capacity >= 50);
+
+ assertTrue("getAppendBuffer(hint=INT32_MAX - len)",
+ s.getAppendBuffer(150, INT32_MAX - s.length(), capacity, errorCode) != nullptr);
+ assertEquals("getAppendBuffer(hint=INT32_MAX - len) success",
+ U_ZERO_ERROR, errorCode.reset());
+ assertTrue("getAppendBuffer(hint=INT32_MAX - len) capacity", capacity >= 150);
+
+ s.appendInvariantChars(u"abc", -1, errorCode);
+ assertEquals("appendInvariantChars(ucharsLen<0)",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+
+ s.appendInvariantChars(nullptr, 1, errorCode);
+ assertEquals("appendInvariantChars(nullptr, 1)",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+
+ s.append("x", INT32_MAX, errorCode);
+ assertEquals("append(INT32_MAX)", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("append(INT32_MAX) length unchanged", 3, s.length());
+
+ s.append("x", INT32_MAX - s.length(), errorCode);
+ assertEquals("append(INT32_MAX - len)", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("append(INT32_MAX - len) length unchanged", 3, s.length());
+
+ constexpr int32_t kChunkLen = 0x30000000;
+ CharString chunk;
+ char* buf = chunk.getAppendBuffer(kChunkLen, kChunkLen, capacity, errorCode);
+ if (buf != nullptr && errorCode.isSuccess()) {
+ uprv_memset(buf, 'a', kChunkLen);
+ chunk.append(buf, kChunkLen, errorCode);
+ CharString dest;
+ int64_t total = 0;
+ for (int32_t i = 0; i < 3; ++i) {
+ int32_t prevLen = dest.length();
+ dest.append(chunk, errorCode);
+ total += kChunkLen;
+ if (total < INT32_MAX) {
+ if (errorCode.isFailure()) {
+ assertEquals("append allocation failure",
+ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
+ break;
+ }
+ assertEquals("dest.length()", static_cast<int32_t>(total), dest.length());
+ } else {
+ assertEquals("append overflow", U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("dest.length() unchanged", prevLen, dest.length());
+ }
+ }
+ if (dest.length() == 2 * kChunkLen) {
+ int32_t remain = (INT32_MAX - 1) - dest.length();
+ dest.append(chunk.data(), remain, errorCode);
+ if (errorCode.isSuccess()) {
+ assertEquals("dest at max length", INT32_MAX - 1, dest.length());
+
+ dest.append('a', errorCode);
+ assertEquals("append(char) overflow",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("dest.length() after append(char)", INT32_MAX - 1, dest.length());
+
+ dest.append("a", 1, errorCode);
+ assertEquals("append(char*, 1) overflow",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("dest.length() after append(char*, 1)",
+ INT32_MAX - 1, dest.length());
+
+ dest.appendInvariantChars(u"a", 1, errorCode);
+ assertEquals("appendInvariantChars(1) overflow",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("dest.length() after appendInvariantChars(1)",
+ INT32_MAX - 1, dest.length());
+
+ dest.appendInvariantChars(u"ab", 2, errorCode);
+ assertEquals("appendInvariantChars(2) overflow",
+ U_ILLEGAL_ARGUMENT_ERROR, errorCode.reset());
+ assertEquals("dest.length() after appendInvariantChars(2)",
+ INT32_MAX - 1, dest.length());
+ } else {
+ assertEquals("append remain allocation failure",
+ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
+ }
+ }
+ } else {
+ // Allocating 768 MiB (kChunkLen) can legitimately fail on 32-bit
+ // platforms or memory-constrained test runners.
+ assertEquals("chunk allocation failure",
+ U_MEMORY_ALLOCATION_ERROR, errorCode.reset());
+ }
+ }
}
void
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page