Skip to content

Commit 8dbae6a

Browse files
author
Mark Lam
committed
Check for out of memory in JSC::globalFuncEscape() and JSC::globalFuncUnescape().
https://bugs.webkit.org/show_bug.cgi?id=227962 rdar://78392251 Reviewed by Yusuke Suzuki. JSTests: * stress/out-of-memory-in-globalFuncUnescape.js: Added. Source/JavaScriptCore: * runtime/JSGlobalObjectFunctions.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): Canonical link: https://commits.webkit.org/239664@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@279915 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 1c5615e commit 8dbae6a

4 files changed

Lines changed: 60 additions & 16 deletions

File tree

JSTests/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2021-07-14 Mark Lam <mark.lam@apple.com>
2+
3+
Check for out of memory in JSC::globalFuncEscape() and JSC::globalFuncUnescape().
4+
https://bugs.webkit.org/show_bug.cgi?id=227962
5+
rdar://78392251
6+
7+
Reviewed by Yusuke Suzuki.
8+
9+
* stress/out-of-memory-in-globalFuncUnescape.js: Added.
10+
111
2021-07-14 Mark Lam <mark.lam@apple.com>
212

313
Placate exception checker validation in operationObjectAssignUntyped.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ if $buildType == "release" && !$memoryLimited then runDefault else skip end
2+
3+
var exception;
4+
try {
5+
unescape('\u0100'.repeat(2**30));
6+
} catch (e) {
7+
exception = e;
8+
}
9+
10+
if (exception != "RangeError: Out of memory")
11+
throw "FAILED";

Source/JavaScriptCore/ChangeLog

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2021-07-14 Mark Lam <mark.lam@apple.com>
2+
3+
Check for out of memory in JSC::globalFuncEscape() and JSC::globalFuncUnescape().
4+
https://bugs.webkit.org/show_bug.cgi?id=227962
5+
rdar://78392251
6+
7+
Reviewed by Yusuke Suzuki.
8+
9+
* runtime/JSGlobalObjectFunctions.cpp:
10+
(JSC::JSC_DEFINE_HOST_FUNCTION):
11+
112
2021-07-14 Yusuke Suzuki <ysuzuki@apple.com>
213

314
libpas executable-allocator should reserve more than 256KB for non-fail region at least

Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncEncodeURIComponent, (JSGlobalObject* globalOb
577577

578578
JSC_DEFINE_HOST_FUNCTION(globalFuncEscape, (JSGlobalObject* globalObject, CallFrame* callFrame))
579579
{
580-
return JSValue::encode(toStringView(globalObject, callFrame->argument(0), [&] (StringView view) {
580+
return JSValue::encode(toStringView(globalObject, callFrame->argument(0), [&] (StringView view) -> JSString* {
581581
static const Bitmap<256> doNotEscape = makeCharacterBitmap(
582582
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
583583
"abcdefghijklmnopqrstuvwxyz"
@@ -586,7 +586,9 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncEscape, (JSGlobalObject* globalObject, CallFr
586586
);
587587

588588
VM& vm = globalObject->vm();
589-
StringBuilder builder;
589+
auto scope = DECLARE_THROW_SCOPE(vm);
590+
591+
StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
590592
if (view.is8Bit()) {
591593
const LChar* c = view.characters8();
592594
for (unsigned k = 0; k < view.length(); k++, c++) {
@@ -596,33 +598,39 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncEscape, (JSGlobalObject* globalObject, CallFr
596598
else
597599
builder.append('%', hex(u, 2));
598600
}
599-
return jsString(vm, builder.toString());
601+
} else {
602+
const UChar* c = view.characters16();
603+
for (unsigned k = 0; k < view.length(); k++, c++) {
604+
UChar u = c[0];
605+
if (u >= doNotEscape.size())
606+
builder.append("%u", hex(static_cast<uint8_t>(u >> 8), 2), hex(static_cast<uint8_t>(u), 2));
607+
else if (doNotEscape.get(static_cast<LChar>(u)))
608+
builder.append(*c);
609+
else
610+
builder.append('%', hex(u, 2));
611+
}
600612
}
601613

602-
const UChar* c = view.characters16();
603-
for (unsigned k = 0; k < view.length(); k++, c++) {
604-
UChar u = c[0];
605-
if (u >= doNotEscape.size())
606-
builder.append("%u", hex(static_cast<uint8_t>(u >> 8), 2), hex(static_cast<uint8_t>(u), 2));
607-
else if (doNotEscape.get(static_cast<LChar>(u)))
608-
builder.append(*c);
609-
else
610-
builder.append('%', hex(u, 2));
614+
if (UNLIKELY(builder.hasOverflowed())) {
615+
throwOutOfMemoryError(globalObject, scope);
616+
return { };
611617
}
612-
613618
return jsString(vm, builder.toString());
614619
}));
615620
}
616621

617622
JSC_DEFINE_HOST_FUNCTION(globalFuncUnescape, (JSGlobalObject* globalObject, CallFrame* callFrame))
618623
{
619-
return JSValue::encode(toStringView(globalObject, callFrame->argument(0), [&] (StringView view) {
624+
return JSValue::encode(toStringView(globalObject, callFrame->argument(0), [&] (StringView view) -> JSString* {
620625
// We use int for k and length intentionally since we would like to evaluate
621626
// the condition `k <= length -6` even if length is less than 6.
622627
int k = 0;
623628
int length = view.length();
624629

625-
StringBuilder builder;
630+
VM& vm = globalObject->vm();
631+
auto scope = DECLARE_THROW_SCOPE(vm);
632+
633+
StringBuilder builder(StringBuilder::OverflowHandler::RecordOverflow);
626634
builder.reserveCapacity(length);
627635

628636
if (view.is8Bit()) {
@@ -666,7 +674,11 @@ JSC_DEFINE_HOST_FUNCTION(globalFuncUnescape, (JSGlobalObject* globalObject, Call
666674
}
667675
}
668676

669-
return jsString(globalObject->vm(), builder.toString());
677+
if (UNLIKELY(builder.hasOverflowed())) {
678+
throwOutOfMemoryError(globalObject, scope);
679+
return { };
680+
}
681+
return jsString(vm, builder.toString());
670682
}));
671683
}
672684

0 commit comments

Comments
 (0)