[runtime] Check for overflow when serializing Strings for JSON.

Previously we would shift the length of the string by three, which
could overflow with the new larger string length limit. Now we check
that the length will fit without extra allocation before and after
the shift, because really large strings will never fit, and will
always go to the Checked case.

Bug: chromium:748069, v8:6148
Change-Id: I41cac14b0fde6c5e8ca92305a052cbb743111554
Reviewed-on: https://chromium-review.googlesource.com/584611
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46896}
This commit is contained in:
Peter Marshall 2017-07-26 12:56:11 +02:00 committed by Commit Bot
parent 7d3c47f3ea
commit 8315422762
3 changed files with 28 additions and 7 deletions

View File

@ -635,12 +635,9 @@ template <typename SrcChar, typename DestChar>
void JsonStringifier::SerializeString_(Handle<String> string) {
int length = string->length();
builder_.Append<uint8_t, DestChar>('"');
// We make a rough estimate to find out if the current string can be
// serialized without allocating a new string part. The worst case length of
// an escaped character is 6. Shifting the remainin string length right by 3
// is a more pessimistic estimate, but faster to calculate.
int worst_case_length = length << 3;
if (builder_.CurrentPartCanFit(worst_case_length)) {
// We might be able to fit the whole escaped string in the current string
// part, or we might need to allocate.
if (int worst_case_length = builder_.EscapedLengthIfCurrentPartFits(length)) {
DisallowHeapAllocation no_gc;
Vector<const SrcChar> vector = string->GetCharVector<SrcChar>();
IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend(
@ -657,7 +654,6 @@ void JsonStringifier::SerializeString_(Handle<String> string) {
}
}
}
builder_.Append<uint8_t, DestChar>('"');
}

View File

@ -304,6 +304,19 @@ class IncrementalStringBuilder {
return part_length_ - current_index_ > length;
}
// We make a rough estimate to find out if the current string can be
// serialized without allocating a new string part. The worst case length of
// an escaped character is 6. Shifting the remaining string length right by 3
// is a more pessimistic estimate, but faster to calculate.
INLINE(int EscapedLengthIfCurrentPartFits(int length)) {
if (length > kMaxPartLength) return 0;
STATIC_ASSERT((kMaxPartLength << 3) <= String::kMaxLength);
// This shift will not overflow because length is already less than the
// maximum part length.
int worst_case_length = length << 3;
return CurrentPartCanFit(worst_case_length) ? worst_case_length : 0;
}
void AppendString(Handle<String> string);
MaybeHandle<String> Finish();

View File

@ -0,0 +1,12 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
try {
var a = 'a'.repeat(1 << 28);
} catch (e) {
// If the allocation fails, we don't care, because we can't cause the
// overflow.
}
// Cause an overflow in worst-case calculation for string replacement.
JSON.stringify(a);