[SCM] WebKit Debian packaging branch, webkit-1.2, updated. 1.2.5-1500-gb65db3c
Huzaifa Sidhpurwala
huzaifas at redhat.com
Tue Jan 11 11:41:53 UTC 2011
The following commit has been merged in the webkit-1.2 branch:
commit f236c158708a2116a799174bd2722fd721e663c4
Author: Huzaifa Sidhpurwala <huzaifas at redhat.com>
Date: Thu Dec 2 12:25:51 2010 +0530
Backport crash fix by Huzaifa Sidhpurwala <huzaifas at redhat.com>
Original authors: oliver at apple.com
mrowe at apple.com
darin at apple.com
https://bugs.webkit.org/show_bug.cgi?id=41351
Clamp the number of arguments supported by function.apply
JavaScriptCore:
Add clamping logic to function.apply similar to that enforced by firefox.
We have a smaller clamp than firefox as our calling convention means that stack
usage is proportional to argument count -- the firefox limit is larger
than you could actually call.
Make Arguments::MaxArguments clamping work for numbers >= 0x80000000 in
the interpreter as well as the JIT.
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Arguments.h:
(JSC::Arguments::):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute): Be slightly more consistent in using uint32_t to prevent
warnings about comparisons between signed and unsigned types, and attempts to call an overload
of std::min that doesn't exist.
* interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute):
Fix signed integer overflow problem in op_load_varargs handling. 0xFFFFFFFF was read as -1.
LayoutTests:
* fast/js/function-apply-many-args-expected.txt: Added.
* fast/js/function-apply-many-args.html: Added.
* fast/js/script-tests/function-apply-many-args.js: Added.
* fast/js/function-apply-expected.txt: Updated to expect success.
* fast/js/script-tests/function-apply.js: Added test cases.
Backported from the following development branch commits:
http://trac.webkit.org/changeset/62432
http://trac.webkit.org/changeset/62433
http://trac.webkit.org/changeset/62464
http://trac.webkit.org/changeset/62456
diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp
index b6e9161..2fcdae3 100644
--- a/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/JavaScriptCore/interpreter/Interpreter.cpp
@@ -3454,9 +3454,10 @@ skip_id_custom_self:
int argsOffset = vPC[2].u.operand;
JSValue arguments = callFrame->r(argsOffset).jsValue();
- int32_t argCount = 0;
+ uint32_t argCount = 0;
if (!arguments) {
- argCount = (uint32_t)(callFrame->argumentCount()) - 1;
+ argCount = (uint32_t)(callFrame->argumentCount());
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3464,9 +3465,9 @@ skip_id_custom_self:
goto vm_throw;
}
ASSERT(!callFrame->callee()->isHostFunction());
- int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
- int32_t inplaceArgs = min(argCount, expectedParams);
- int32_t i = 0;
+ uint32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
+ uint32_t inplaceArgs = min(argCount, expectedParams);
+ uint32_t i = 0;
Register* argStore = callFrame->registers() + argsOffset;
// First step is to copy the "expected" parameters from their normal location relative to the callframe
@@ -3483,6 +3484,7 @@ skip_id_custom_self:
if (asObject(arguments)->classInfo() == &Arguments::info) {
Arguments* args = asArguments(arguments);
argCount = args->numProvidedArguments(callFrame);
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3493,6 +3495,7 @@ skip_id_custom_self:
} else if (isJSArray(&callFrame->globalData(), arguments)) {
JSArray* array = asArray(arguments);
argCount = array->length();
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3503,6 +3506,7 @@ skip_id_custom_self:
} else if (asObject(arguments)->inherits(&JSArray::info)) {
JSObject* argObject = asObject(arguments);
argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+ argCount = min<uint32_t>(argCount, Arguments::MaxArguments);
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -3510,7 +3514,7 @@ skip_id_custom_self:
goto vm_throw;
}
Register* argsBuffer = callFrame->registers() + argsOffset;
- for (int32_t i = 0; i < argCount; ++i) {
+ for (uint32_t i = 0; i < argCount; ++i) {
argsBuffer[i] = asObject(arguments)->get(callFrame, i);
CHECK_FOR_EXCEPTION();
}
diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp
index 03b16b4..d9cd7b0 100644
--- a/JavaScriptCore/jit/JITStubs.cpp
+++ b/JavaScriptCore/jit/JITStubs.cpp
@@ -2134,6 +2134,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs)
if (!arguments) {
int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1;
argCount = providedParams;
+ argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -2169,6 +2170,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs)
if (asObject(arguments)->classInfo() == &Arguments::info) {
Arguments* argsObject = asArguments(arguments);
argCount = argsObject->numProvidedArguments(callFrame);
+ argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -2179,6 +2181,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs)
} else if (isJSArray(&callFrame->globalData(), arguments)) {
JSArray* array = asArray(arguments);
argCount = array->length();
+ argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
@@ -2189,6 +2192,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs)
} else if (asObject(arguments)->inherits(&JSArray::info)) {
JSObject* argObject = asObject(arguments);
argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+ argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
Register* newEnd = callFrame->registers() + sizeDelta;
if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h
index 9797e08..704b13e 100644
--- a/JavaScriptCore/runtime/Arguments.h
+++ b/JavaScriptCore/runtime/Arguments.h
@@ -55,6 +55,10 @@ namespace JSC {
class Arguments : public JSObject {
public:
+ // Use an enum because otherwise gcc insists on doing a memory
+ // read
+ enum { MaxArguments = 0x10000 };
+
enum NoParametersType { NoParameters };
Arguments(CallFrame*);
diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp
index d3ef44c..ae9e038 100644
--- a/JavaScriptCore/runtime/JSArray.cpp
+++ b/JavaScriptCore/runtime/JSArray.cpp
@@ -948,10 +948,10 @@ void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
{
- ASSERT(m_storage->m_length == maxSize);
+ ASSERT(m_storage->m_length >= maxSize);
UNUSED_PARAM(maxSize);
JSValue* vector = m_storage->m_vector;
- unsigned vectorEnd = min(m_storage->m_length, m_vectorLength);
+ unsigned vectorEnd = min(maxSize, m_vectorLength);
unsigned i = 0;
for (; i < vectorEnd; ++i) {
JSValue& v = vector[i];
@@ -960,7 +960,7 @@ void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSiz
buffer[i] = v;
}
- for (; i < m_storage->m_length; ++i)
+ for (; i < maxSize; ++i)
buffer[i] = get(exec, i);
}
diff --git a/LayoutTests/fast/js/function-apply-expected.txt b/LayoutTests/fast/js/function-apply-expected.txt
index 63ef8db..018163f 100644
--- a/LayoutTests/fast/js/function-apply-expected.txt
+++ b/LayoutTests/fast/js/function-apply-expected.txt
@@ -30,6 +30,12 @@ PASS arrayApplyChangeLength1() is 2
PASS arrayApplyChangeLength2() is 2
PASS arrayApplyChangeLength3() is 2
PASS arrayApplyChangeLength4() is 0
+PASS var a = []; a.length = 0xFFFE; [].constructor.apply('', a).length is 0xFFFE
+PASS var a = []; a.length = 0xFFFF; [].constructor.apply('', a).length is 0xFFFF
+PASS var a = []; a.length = 0x10000; [].constructor.apply('', a).length is 0x10000
+PASS var a = []; a.length = 0x10001; [].constructor.apply('', a).length is 0x10000
+PASS var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length is 0x10000
+PASS var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length is 0x10000
PASS successfullyParsed is true
TEST COMPLETE
diff --git a/LayoutTests/fast/js/function-apply-many-args-expected.txt b/LayoutTests/fast/js/function-apply-many-args-expected.txt
new file mode 100644
index 0000000..a616b2a
--- /dev/null
+++ b/LayoutTests/fast/js/function-apply-many-args-expected.txt
@@ -0,0 +1,45 @@
+Tests that we truncate arguments beyond a certain threshold.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS f.apply(null) is 0
+PASS f.apply(null, []) is 0
+PASS f.apply(null, [1]) is 1
+PASS f.apply(null, new Array(10)) is 10
+PASS f.apply(null, new Array(1000)) is 1000
+PASS f.apply(null, new Array(65536)) is 65536
+PASS f.apply(null, new Array(65537)) is 65536
+PASS f.apply(null, new Array(65537)) is 65536
+PASS f.apply(null, bigArray) is 65536
+PASS g.apply(null) is 0
+PASS g.apply(null, []) is 0
+PASS g.apply(null, [1]) is 1
+PASS g.apply(null, new Array(10)) is 10
+PASS g.apply(null, new Array(1000)) is 1000
+PASS g.apply(null, new Array(65536)) is 65536
+PASS g.apply(null, new Array(65537)) is 65536
+PASS g.apply(null, new Array(65537)) is 65536
+PASS g.apply(null, bigArray) is 65536
+PASS h.apply(null) is 0
+PASS h.apply(null, []) is 0
+PASS h.apply(null, [1]) is 1
+PASS h.apply(null, new Array(10)) is 10
+PASS h.apply(null, new Array(1000)) is 1000
+PASS h.apply(null, new Array(65536)) is 65536
+PASS h.apply(null, new Array(65537)) is 65536
+PASS h.apply(null, new Array(65537)) is 65536
+PASS h.apply(null, bigArray) is 65536
+PASS i.apply(null) is 0
+PASS i.apply(null, []) is 0
+PASS i.apply(null, [1]) is 1
+PASS i.apply(null, new Array(10)) is 10
+PASS i.apply(null, new Array(1000)) is 1000
+PASS i.apply(null, new Array(65536)) is 65536
+PASS i.apply(null, new Array(65537)) is 65536
+PASS i.apply(null, new Array(65537)) is 65536
+PASS i.apply(null, bigArray) is 65536
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/js/function-apply-many-args.html b/LayoutTests/fast/js/function-apply-many-args.html
new file mode 100644
index 0000000..bd15769
--- /dev/null
+++ b/LayoutTests/fast/js/function-apply-many-args.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/function-apply-many-args.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/script-tests/function-apply-aliased.js b/LayoutTests/fast/js/script-tests/function-apply-aliased.js
index 0e09632..f011133 100644
--- a/LayoutTests/fast/js/script-tests/function-apply-aliased.js
+++ b/LayoutTests/fast/js/script-tests/function-apply-aliased.js
@@ -44,10 +44,17 @@ shouldBe("myFunctionWithApply.apply(myObject, arg1Array)", '[myFunctionWithApply
shouldBe("forwarder(myFunctionWithApply, myObject, arg1Array)", '[myFunctionWithApply, "myFunctionWithApply.apply", myObject]');
shouldBe("myFunctionWithApply.aliasedApply(myObject, arg1Array)", '[myObject, "myFunctionWithApply", "arg1"]');
-// Blow the stack with a sparse array
-shouldThrow("myFunction.apply(null, new Array(5000000))");
-// Blow the stack with a sparse array that is sufficiently large to cause int overflow
-shouldThrow("myFunction.apply(null, new Array(1 << 30))");
+function stackOverflowTest() {
+ try {
+ var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;
+ stackOverflowTest();
+ } catch(e) {
+ // Blow the stack with a sparse array
+ shouldThrow("myFunction.apply(null, new Array(5000000))");
+ // Blow the stack with a sparse array that is sufficiently large to cause int overflow
+ shouldThrow("myFunction.apply(null, new Array(1 << 30))");
+ }
+}
// Blow the stack recursing with arguments
shouldThrow("recurseArguments.apply(null, new Array(50000))");
diff --git a/LayoutTests/fast/js/script-tests/function-apply-many-args.js b/LayoutTests/fast/js/script-tests/function-apply-many-args.js
new file mode 100644
index 0000000..6c67bf2
--- /dev/null
+++ b/LayoutTests/fast/js/script-tests/function-apply-many-args.js
@@ -0,0 +1,48 @@
+description("Tests that we truncate arguments beyond a certain threshold.");
+
+function f() { return arguments.length; }
+function g() { return f.apply(null, arguments); }
+function h() { arguments; return f.apply(null, arguments); }
+function i() { arguments[arguments.length] = 0; return f.apply(null, arguments); }
+var bigArray = [];
+for (var j = 0; j < 100000; j++)
+ bigArray.push(null);
+
+shouldBe("f.apply(null)", "0");
+shouldBe("f.apply(null, [])", "0");
+shouldBe("f.apply(null, [1])", "1");
+shouldBe("f.apply(null, new Array(10))", "10");
+shouldBe("f.apply(null, new Array(1000))", "1000");
+shouldBe("f.apply(null, new Array(65536))", "65536");
+shouldBe("f.apply(null, new Array(65537))", "65536");
+shouldBe("f.apply(null, new Array(65537))", "65536");
+shouldBe("f.apply(null, bigArray)", "65536");
+shouldBe("g.apply(null)", "0");
+shouldBe("g.apply(null, [])", "0");
+shouldBe("g.apply(null, [1])", "1");
+shouldBe("g.apply(null, new Array(10))", "10");
+shouldBe("g.apply(null, new Array(1000))", "1000");
+shouldBe("g.apply(null, new Array(65536))", "65536");
+shouldBe("g.apply(null, new Array(65537))", "65536");
+shouldBe("g.apply(null, new Array(65537))", "65536");
+shouldBe("g.apply(null, bigArray)", "65536");
+shouldBe("h.apply(null)", "0");
+shouldBe("h.apply(null, [])", "0");
+shouldBe("h.apply(null, [1])", "1");
+shouldBe("h.apply(null, new Array(10))", "10");
+shouldBe("h.apply(null, new Array(1000))", "1000");
+shouldBe("h.apply(null, new Array(65536))", "65536");
+shouldBe("h.apply(null, new Array(65537))", "65536");
+shouldBe("h.apply(null, new Array(65537))", "65536");
+shouldBe("h.apply(null, bigArray)", "65536");
+shouldBe("i.apply(null)", "0");
+shouldBe("i.apply(null, [])", "0");
+shouldBe("i.apply(null, [1])", "1");
+shouldBe("i.apply(null, new Array(10))", "10");
+shouldBe("i.apply(null, new Array(1000))", "1000");
+shouldBe("i.apply(null, new Array(65536))", "65536");
+shouldBe("i.apply(null, new Array(65537))", "65536");
+shouldBe("i.apply(null, new Array(65537))", "65536");
+shouldBe("i.apply(null, bigArray)", "65536");
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/js/script-tests/function-apply.js b/LayoutTests/fast/js/script-tests/function-apply.js
index e58d909..57aaea1 100644
--- a/LayoutTests/fast/js/script-tests/function-apply.js
+++ b/LayoutTests/fast/js/script-tests/function-apply.js
@@ -284,4 +284,11 @@ shouldBe("arrayApplyChangeLength2()", "2");
shouldBe("arrayApplyChangeLength3()", "2");
shouldBe("arrayApplyChangeLength4()", "0");
+shouldBe("var a = []; a.length = 0xFFFE; [].constructor.apply('', a).length", "0xFFFE");
+shouldBe("var a = []; a.length = 0xFFFF; [].constructor.apply('', a).length", "0xFFFF");
+shouldBe("var a = []; a.length = 0x10000; [].constructor.apply('', a).length", "0x10000");
+shouldBe("var a = []; a.length = 0x10001; [].constructor.apply('', a).length", "0x10000");
+shouldBe("var a = []; a.length = 0xFFFFFFFE; [].constructor.apply('', a).length", "0x10000");
+shouldBe("var a = []; a.length = 0xFFFFFFFF; [].constructor.apply('', a).length", "0x10000");
+
var successfullyParsed = true;
--
WebKit Debian packaging
More information about the Pkg-webkit-commits
mailing list