Diff
Modified: trunk/JSTests/ChangeLog (239438 => 239439)
--- trunk/JSTests/ChangeLog 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/JSTests/ChangeLog 2018-12-20 16:06:44 UTC (rev 239439)
@@ -1,3 +1,14 @@
+2018-12-20 Tadeu Zagallo <[email protected]>
+
+ WTF::String and StringImpl overflow MaxLength
+ https://bugs.webkit.org/show_bug.cgi?id=192853
+ <rdar://problem/45726906>
+
+ Reviewed by Mark Lam.
+
+ * stress/string-16bit-repeat-overflow.js: Added.
+ (catch):
+
2018-12-19 Ross Kirsling <[email protected]>
Unreviewed follow-up to r192914.
Added: trunk/JSTests/stress/string-16bit-repeat-overflow.js (0 => 239439)
--- trunk/JSTests/stress/string-16bit-repeat-overflow.js (rev 0)
+++ trunk/JSTests/stress/string-16bit-repeat-overflow.js 2018-12-20 16:06:44 UTC (rev 239439)
@@ -0,0 +1,9 @@
+var exception;
+try {
+ print('\ud000'.repeat(2**30));
+} catch (e) {
+ exception = e;
+}
+
+if (exception != "Error: Out of memory")
+ throw "FAILED";
Modified: trunk/Source/WTF/ChangeLog (239438 => 239439)
--- trunk/Source/WTF/ChangeLog 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/Source/WTF/ChangeLog 2018-12-20 16:06:44 UTC (rev 239439)
@@ -1,3 +1,40 @@
+2018-12-20 Tadeu Zagallo <[email protected]>
+
+ Consistently use MaxLength for all WTF strings
+ https://bugs.webkit.org/show_bug.cgi?id=192853
+ <rdar://problem/45726906>
+
+ Reviewed by Mark Lam.
+
+ MaxLength was introduced to be INT_MAX for WTF::String and StringImpl,
+ but all the assertions were still done using UINT_MAX. Change it to
+ use MaxLength for all checks.
+
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::createUninitializedInternalNonEmpty):
+ (WTF::StringImpl::reallocateInternal):
+ (WTF::StringImpl::create):
+ (WTF::StringImpl::convertToLowercaseWithoutLocale):
+ (WTF::StringImpl::convertToUppercaseWithoutLocale):
+ (WTF::StringImpl::convertToLowercaseWithLocale):
+ (WTF::StringImpl::convertToUppercaseWithLocale):
+ (WTF::StringImpl::foldCase):
+ (WTF::StringImpl::find):
+ (WTF::StringImpl::replace):
+ (WTF::StringImpl::utf8ForCharacters):
+ (WTF::StringImpl::tryGetUtf8ForRange const):
+ * wtf/text/StringImpl.h:
+ (WTF::lengthOfNullTerminatedString):
+ (WTF::StringImpl::tryCreateUninitialized):
+ (WTF::StringImpl::adopt):
+ (WTF::StringImpl::maxInternalLength):
+ * wtf/text/WTFString.cpp:
+ (WTF::String::append):
+ (WTF::String::insert):
+ (WTF::String::fromUTF8):
+ * wtf/text/WTFString.h:
+ (WTF::String::reverseFind const):
+
2018-12-19 Chris Dumez <[email protected]>
wtf/Optional.h: move-constructor and move-assignment operator should disengage the value being moved from
Modified: trunk/Source/WTF/wtf/text/StringImpl.cpp (239438 => 239439)
--- trunk/Source/WTF/wtf/text/StringImpl.cpp 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/Source/WTF/wtf/text/StringImpl.cpp 2018-12-20 16:06:44 UTC (rev 239439)
@@ -193,7 +193,7 @@
// Allocate a single buffer large enough to contain the StringImpl
// struct as well as the data which it contains. This removes one
// heap allocation from this call.
- if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType)))
+ if (length > maxInternalLength<CharacterType>())
CRASH();
StringImpl* string = static_cast<StringImpl*>(fastMalloc(allocationSize<CharacterType>(length)));
@@ -222,7 +222,7 @@
}
// Same as createUninitialized() except here we use fastRealloc.
- if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType)))
+ if (length > maxInternalLength<CharacterType>())
return makeUnexpected(UTF8ConversionError::OutOfMemory);
originalString->~StringImpl();
@@ -307,7 +307,7 @@
if (!string)
return *empty();
size_t length = strlen(reinterpret_cast<const char*>(string));
- if (length > std::numeric_limits<unsigned>::max())
+ if (length > MaxLength)
CRASH();
return create(string, length);
}
@@ -377,7 +377,7 @@
return newImpl;
}
- if (m_length > static_cast<unsigned>(std::numeric_limits<int32_t>::max()))
+ if (m_length > MaxLength)
CRASH();
int32_t length = m_length;
@@ -429,7 +429,7 @@
// few actual calls to upper() are no-ops, so it wouldn't be worth
// the extra time for pre-scanning.
- if (m_length > static_cast<unsigned>(std::numeric_limits<int32_t>::max()))
+ if (m_length > MaxLength)
CRASH();
int32_t length = m_length;
@@ -541,7 +541,7 @@
// this last part into a shared function that takes a locale string, since this is
// just like the end of that function.
- if (m_length > static_cast<unsigned>(std::numeric_limits<int32_t>::max()))
+ if (m_length > MaxLength)
CRASH();
int length = m_length;
@@ -572,7 +572,7 @@
if (!needsTurkishCasingRules(localeIdentifier) || find('i') == notFound)
return convertToUppercaseWithoutLocale();
- if (m_length > static_cast<unsigned>(std::numeric_limits<int32_t>::max()))
+ if (m_length > MaxLength)
CRASH();
int length = m_length;
@@ -657,7 +657,7 @@
}
}
- if (m_length > static_cast<unsigned>(std::numeric_limits<int32_t>::max()))
+ if (m_length > MaxLength)
CRASH();
auto upconvertedCharacters = StringView(*this).upconvertedCharacters();
@@ -935,7 +935,7 @@
if (!matchString)
return notFound;
size_t matchStringLength = strlen(reinterpret_cast<const char*>(matchString));
- if (matchStringLength > std::numeric_limits<unsigned>::max())
+ if (matchStringLength > MaxLength)
CRASH();
unsigned matchLength = matchStringLength;
if (!matchLength)
@@ -1307,7 +1307,7 @@
if (!lengthToReplace && !lengthToInsert)
return *this;
- if ((length() - lengthToReplace) >= (std::numeric_limits<unsigned>::max() - lengthToInsert))
+ if ((length() - lengthToReplace) >= (MaxLength - lengthToInsert))
CRASH();
if (is8Bit() && (!string || string->is8Bit())) {
@@ -1364,12 +1364,12 @@
if (!matchCount)
return *this;
- if (repStrLength && matchCount > std::numeric_limits<unsigned>::max() / repStrLength)
+ if (repStrLength && matchCount > MaxLength / repStrLength)
CRASH();
unsigned replaceSize = matchCount * repStrLength;
unsigned newSize = m_length - matchCount;
- if (newSize >= (std::numeric_limits<unsigned>::max() - replaceSize))
+ if (newSize >= (MaxLength - replaceSize))
CRASH();
newSize += replaceSize;
@@ -1440,12 +1440,12 @@
if (!matchCount)
return *this;
- if (repStrLength && matchCount > std::numeric_limits<unsigned>::max() / repStrLength)
+ if (repStrLength && matchCount > MaxLength / repStrLength)
CRASH();
unsigned replaceSize = matchCount * repStrLength;
unsigned newSize = m_length - matchCount;
- if (newSize >= (std::numeric_limits<unsigned>::max() - replaceSize))
+ if (newSize >= (MaxLength - replaceSize))
CRASH();
newSize += replaceSize;
@@ -1525,10 +1525,10 @@
return *this;
unsigned newSize = m_length - matchCount * patternLength;
- if (repStrLength && matchCount > std::numeric_limits<unsigned>::max() / repStrLength)
+ if (repStrLength && matchCount > MaxLength / repStrLength)
CRASH();
- if (newSize > (std::numeric_limits<unsigned>::max() - matchCount * repStrLength))
+ if (newSize > (MaxLength - matchCount * repStrLength))
CRASH();
newSize += matchCount * repStrLength;
@@ -1804,7 +1804,7 @@
{
if (!length)
return CString("", 0);
- if (length > std::numeric_limits<unsigned>::max() / 3)
+ if (length > MaxLength / 3)
return makeUnexpected(UTF8ConversionError::OutOfMemory);
Vector<char, 1024> bufferVector(length * 3);
char* buffer = bufferVector.data();
@@ -1818,7 +1818,7 @@
{
if (!length)
return CString("", 0);
- if (length > std::numeric_limits<unsigned>::max() / 3)
+ if (length > MaxLength / 3)
return makeUnexpected(UTF8ConversionError::OutOfMemory);
Vector<char, 1024> bufferVector(length * 3);
char* buffer = bufferVector.data();
@@ -1846,7 +1846,7 @@
// * We could allocate a CStringBuffer with an appropriate size to
// have a good chance of being able to write the string into the
// buffer without reallocing (say, 1.5 x length).
- if (length > std::numeric_limits<unsigned>::max() / 3)
+ if (length > MaxLength / 3)
return makeUnexpected(UTF8ConversionError::OutOfMemory);
Vector<char, 1024> bufferVector(length * 3);
Modified: trunk/Source/WTF/wtf/text/StringImpl.h (239438 => 239439)
--- trunk/Source/WTF/wtf/text/StringImpl.h 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/Source/WTF/wtf/text/StringImpl.h 2018-12-20 16:06:44 UTC (rev 239439)
@@ -379,7 +379,7 @@
// its own copy of the string.
Ref<StringImpl> isolatedCopy() const;
- WTF_EXPORT_PRIVATE Ref<StringImpl> substring(unsigned position, unsigned length = std::numeric_limits<unsigned>::max());
+ WTF_EXPORT_PRIVATE Ref<StringImpl> substring(unsigned position, unsigned length = MaxLength);
UChar at(unsigned) const;
UChar operator[](unsigned i) const { return at(i); }
@@ -437,8 +437,8 @@
WTF_EXPORT_PRIVATE size_t findIgnoringASCIICase(const StringImpl*) const;
WTF_EXPORT_PRIVATE size_t findIgnoringASCIICase(const StringImpl*, unsigned startOffset) const;
- WTF_EXPORT_PRIVATE size_t reverseFind(UChar, unsigned index = std::numeric_limits<unsigned>::max());
- WTF_EXPORT_PRIVATE size_t reverseFind(StringImpl*, unsigned index = std::numeric_limits<unsigned>::max());
+ WTF_EXPORT_PRIVATE size_t reverseFind(UChar, unsigned index = MaxLength);
+ WTF_EXPORT_PRIVATE size_t reverseFind(StringImpl*, unsigned index = MaxLength);
WTF_EXPORT_PRIVATE bool startsWith(const StringImpl*) const;
WTF_EXPORT_PRIVATE bool startsWith(const StringImpl&) const;
@@ -495,6 +495,7 @@
private:
template<typename> static size_t allocationSize(Checked<size_t> tailElementCount);
+ template<typename> static size_t maxInternalLength();
template<typename> static size_t tailOffset();
bool requiresCopy() const;
@@ -569,10 +570,10 @@
size_t find(const LChar*, unsigned length, CodeUnitMatchFunction, unsigned index = 0);
size_t find(const UChar*, unsigned length, CodeUnitMatchFunction, unsigned index = 0);
-template<typename CharacterType> size_t reverseFindLineTerminator(const CharacterType*, unsigned length, unsigned index = std::numeric_limits<unsigned>::max());
-template<typename CharacterType> size_t reverseFind(const CharacterType*, unsigned length, CharacterType matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
-size_t reverseFind(const UChar*, unsigned length, LChar matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
-size_t reverseFind(const LChar*, unsigned length, UChar matchCharacter, unsigned index = std::numeric_limits<unsigned>::max());
+template<typename CharacterType> size_t reverseFindLineTerminator(const CharacterType*, unsigned length, unsigned index = StringImpl::MaxLength);
+template<typename CharacterType> size_t reverseFind(const CharacterType*, unsigned length, CharacterType matchCharacter, unsigned index = StringImpl::MaxLength);
+size_t reverseFind(const UChar*, unsigned length, LChar matchCharacter, unsigned index = StringImpl::MaxLength);
+size_t reverseFind(const LChar*, unsigned length, UChar matchCharacter, unsigned index = StringImpl::MaxLength);
template<size_t inlineCapacity> bool equalIgnoringNullity(const Vector<UChar, inlineCapacity>&, StringImpl*);
@@ -755,7 +756,7 @@
while (string[length])
++length;
- RELEASE_ASSERT(length < std::numeric_limits<unsigned>::max());
+ RELEASE_ASSERT(length < StringImpl::MaxLength);
return static_cast<unsigned>(length);
}
@@ -954,7 +955,7 @@
return empty();
}
- if (length > ((std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType))) {
+ if (length > maxInternalLength<CharacterType>()) {
output = nullptr;
return nullptr;
}
@@ -973,7 +974,7 @@
{
if (size_t size = vector.size()) {
ASSERT(vector.data());
- if (size > std::numeric_limits<unsigned>::max())
+ if (size > MaxLength)
CRASH();
return adoptRef(*new StringImpl(vector.releaseBuffer(), size));
}
@@ -1112,6 +1113,13 @@
return (tailOffset<T>() + tailElementCount * sizeof(T)).unsafeGet();
}
+template<typename CharacterType>
+inline size_t StringImpl::maxInternalLength()
+{
+ // In order to not overflow the unsigned length, the check for (std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) is needed when sizeof(CharacterType) == 2.
+ return std::min(static_cast<size_t>(MaxLength), (std::numeric_limits<unsigned>::max() - sizeof(StringImpl)) / sizeof(CharacterType));
+}
+
template<typename T> inline size_t StringImpl::tailOffset()
{
#if COMPILER(MSVC)
Modified: trunk/Source/WTF/wtf/text/WTFString.cpp (239438 => 239439)
--- trunk/Source/WTF/wtf/text/WTFString.cpp 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/Source/WTF/wtf/text/WTFString.cpp 2018-12-20 16:06:44 UTC (rev 239439)
@@ -99,7 +99,7 @@
auto length = m_impl->length();
auto otherLength = otherString.m_impl->length();
- if (otherLength > std::numeric_limits<unsigned>::max() - length)
+ if (otherLength > MaxLength - length)
CRASH();
if (m_impl->is8Bit() && otherString.m_impl->is8Bit()) {
@@ -129,7 +129,7 @@
append(static_cast<UChar>(character));
return;
}
- if (m_impl->length() >= std::numeric_limits<unsigned>::max())
+ if (m_impl->length() >= MaxLength)
CRASH();
LChar* data;
auto newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
@@ -150,7 +150,7 @@
append(static_cast<LChar>(character));
return;
}
- if (m_impl->length() >= std::numeric_limits<unsigned>::max())
+ if (m_impl->length() >= MaxLength)
CRASH();
UChar* data;
auto newImpl = StringImpl::createUninitialized(m_impl->length() + 1, data);
@@ -183,7 +183,7 @@
return;
}
- if (lengthToInsert > std::numeric_limits<unsigned>::max() - length())
+ if (lengthToInsert > MaxLength - length())
CRASH();
if (is8Bit() && string.is8Bit()) {
@@ -222,7 +222,7 @@
unsigned strLength = m_impl->length();
if (m_impl->is8Bit()) {
- if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength)
+ if (lengthToAppend > MaxLength - strLength)
CRASH();
LChar* data;
auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data);
@@ -232,7 +232,7 @@
return;
}
- if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength)
+ if (lengthToAppend > MaxLength - strLength)
CRASH();
UChar* data;
auto newImpl = StringImpl::createUninitialized(length() + lengthToAppend, data);
@@ -258,7 +258,7 @@
unsigned strLength = m_impl->length();
ASSERT(charactersToAppend);
- if (lengthToAppend > std::numeric_limits<unsigned>::max() - strLength)
+ if (lengthToAppend > MaxLength - strLength)
CRASH();
UChar* data;
auto newImpl = StringImpl::createUninitialized(strLength + lengthToAppend, data);
@@ -885,7 +885,7 @@
String String::fromUTF8(const LChar* stringStart, size_t length)
{
- if (length > std::numeric_limits<unsigned>::max())
+ if (length > MaxLength)
CRASH();
if (!stringStart)
Modified: trunk/Source/WTF/wtf/text/WTFString.h (239438 => 239439)
--- trunk/Source/WTF/wtf/text/WTFString.h 2018-12-20 11:59:05 UTC (rev 239438)
+++ trunk/Source/WTF/wtf/text/WTFString.h 2018-12-20 16:06:44 UTC (rev 239439)
@@ -194,8 +194,8 @@
size_t find(const LChar* string, unsigned start = 0) const { return m_impl ? m_impl->find(string, start) : notFound; }
// Find the last instance of a single character or string.
- size_t reverseFind(UChar character, unsigned start = std::numeric_limits<unsigned>::max()) const { return m_impl ? m_impl->reverseFind(character, start) : notFound; }
- size_t reverseFind(const String& string, unsigned start = std::numeric_limits<unsigned>::max()) const { return m_impl ? m_impl->reverseFind(string.impl(), start) : notFound; }
+ size_t reverseFind(UChar character, unsigned start = MaxLength) const { return m_impl ? m_impl->reverseFind(character, start) : notFound; }
+ size_t reverseFind(const String& string, unsigned start = MaxLength) const { return m_impl ? m_impl->reverseFind(string.impl(), start) : notFound; }
WTF_EXPORT_PRIVATE Vector<UChar> charactersWithNullTermination() const;
@@ -237,8 +237,8 @@
WTF_EXPORT_PRIVATE void truncate(unsigned length);
WTF_EXPORT_PRIVATE void remove(unsigned position, unsigned length = 1);
- WTF_EXPORT_PRIVATE String substring(unsigned position, unsigned length = std::numeric_limits<unsigned>::max()) const;
- WTF_EXPORT_PRIVATE String substringSharingImpl(unsigned position, unsigned length = std::numeric_limits<unsigned>::max()) const;
+ WTF_EXPORT_PRIVATE String substring(unsigned position, unsigned length = MaxLength) const;
+ WTF_EXPORT_PRIVATE String substringSharingImpl(unsigned position, unsigned length = MaxLength) const;
String left(unsigned length) const { return substring(0, length); }
String right(unsigned length) const { return substring(this->length() - length, length); }