From: Apple Date: Tue, 17 Feb 2015 05:00:49 +0000 (+0000) Subject: JavaScriptCore-1218.35.tar.gz X-Git-Tag: ios-712^0 X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/commitdiff_plain/4be4e30906bcb8ee30b4d189205cb70bad6707ce JavaScriptCore-1218.35.tar.gz --- diff --git a/assembler/MacroAssemblerARM64.h b/assembler/MacroAssemblerARM64.h index 7c9e922..8d0e79c 100644 --- a/assembler/MacroAssemblerARM64.h +++ b/assembler/MacroAssemblerARM64.h @@ -1738,6 +1738,12 @@ public: return branchAdd32(cond, op1, dataTempRegister, dest); } + Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) + { + load32(src, getCachedDataTempRegisterIDAndInvalidate()); + return branchAdd32(cond, dest, dataTempRegister, dest); + } + Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) { return branchAdd32(cond, dest, src, dest); diff --git a/assembler/MacroAssemblerARMv7.h b/assembler/MacroAssemblerARMv7.h index 9cbb71c..f65b1cd 100644 --- a/assembler/MacroAssemblerARMv7.h +++ b/assembler/MacroAssemblerARMv7.h @@ -1477,6 +1477,12 @@ public: return branchAdd32(cond, dest, src, dest); } + Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) + { + load32(src, dataTempRegister); + return branchAdd32(cond, dest, dataTempRegister, dest); + } + Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) { return branchAdd32(cond, dest, imm, dest); diff --git a/dfg/DFGAbstractState.cpp b/dfg/DFGAbstractState.cpp index be83f69..78ebb4a 100644 --- a/dfg/DFGAbstractState.cpp +++ b/dfg/DFGAbstractState.cpp @@ -476,6 +476,7 @@ bool AbstractState::executeEffects(unsigned indexInBlock, Node* node) } case MakeRope: { + node->setCanExit(true); forNode(node).set(m_graph.m_vm.stringStructure.get()); break; } diff --git a/dfg/DFGOperations.cpp b/dfg/DFGOperations.cpp index 860c486..af8212d 100644 --- a/dfg/DFGOperations.cpp +++ b/dfg/DFGOperations.cpp @@ -1643,6 +1643,11 @@ JSCell* DFG_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSStri VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); + if (sumOverflows(left->length(), right->length())) { + throwOutOfMemoryError(exec); + return nullptr; + } + return JSRopeString::create(vm, left, right); } @@ -1651,6 +1656,11 @@ JSCell* DFG_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); + if (sumOverflows(a->length(), b->length(), c->length())) { + throwOutOfMemoryError(exec); + return nullptr; + } + return JSRopeString::create(vm, a, b, c); } diff --git a/dfg/DFGSpeculativeJIT.cpp b/dfg/DFGSpeculativeJIT.cpp index 64f1b4b..bffc37c 100644 --- a/dfg/DFGSpeculativeJIT.cpp +++ b/dfg/DFGSpeculativeJIT.cpp @@ -3244,12 +3244,28 @@ void SpeculativeJIT::compileMakeRope(Node* node) m_jit.storePtr(TrustedImmPtr(0), JITCompiler::Address(resultGPR, JSRopeString::offsetOfFibers() + sizeof(WriteBarrier) * i)); m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfFlags()), scratchGPR); m_jit.load32(JITCompiler::Address(opGPRs[0], JSString::offsetOfLength()), allocatorGPR); + if (!ASSERT_DISABLED) { + JITCompiler::Jump ok = m_jit.branch32( + JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); + m_jit.breakpoint(); + ok.link(&m_jit); + } for (unsigned i = 1; i < numOpGPRs; ++i) { m_jit.and32(JITCompiler::Address(opGPRs[i], JSString::offsetOfFlags()), scratchGPR); - m_jit.add32(JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR); + speculationCheck( + Uncountable, JSValueSource(), nullptr, + m_jit.branchAdd32( + JITCompiler::Overflow, + JITCompiler::Address(opGPRs[i], JSString::offsetOfLength()), allocatorGPR)); } m_jit.and32(JITCompiler::TrustedImm32(JSString::Is8Bit), scratchGPR); m_jit.store32(scratchGPR, JITCompiler::Address(resultGPR, JSString::offsetOfFlags())); + if (!ASSERT_DISABLED) { + JITCompiler::Jump ok = m_jit.branch32( + JITCompiler::GreaterThanOrEqual, allocatorGPR, TrustedImm32(0)); + m_jit.breakpoint(); + ok.link(&m_jit); + } m_jit.store32(allocatorGPR, JITCompiler::Address(resultGPR, JSString::offsetOfLength())); switch (numOpGPRs) { diff --git a/jit/JITCall32_64.cpp b/jit/JITCall32_64.cpp index c8be312..85bf3a9 100644 --- a/jit/JITCall32_64.cpp +++ b/jit/JITCall32_64.cpp @@ -269,13 +269,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca return; } + addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); + DataLabelPtr addressOfLinkedFunctionCheck; BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall); Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); END_UNINTERRUPTED_SEQUENCE(sequenceOpCall); addSlowCase(slowCase); - addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex); m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo()); diff --git a/llint/LLIntSlowPaths.cpp b/llint/LLIntSlowPaths.cpp index cf8ded3..49284cd 100644 --- a/llint/LLIntSlowPaths.cpp +++ b/llint/LLIntSlowPaths.cpp @@ -117,6 +117,14 @@ namespace JSC { namespace LLInt { LLINT_END_IMPL(); \ } while (false) +#define LLINT_RETURN_WITH_PC_ADJUSTMENT(value, pcAdjustment) do { \ + JSValue __r_returnValue = (value); \ + LLINT_CHECK_EXCEPTION(); \ + LLINT_OP(1) = __r_returnValue; \ + pc += (pcAdjustment); \ + LLINT_END_IMPL(); \ + } while (false) + #if ENABLE(VALUE_PROFILER) #define LLINT_RETURN_PROFILED(opcode, value) do { \ JSValue __rp_returnValue = (value); \ @@ -727,8 +735,8 @@ LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) JSObject* baseObject = asObject(baseVal); ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); if (baseObject->structure()->typeInfo().implementsHasInstance()) { - pc += pc[4].u.operand; - LLINT_RETURN(jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value))); + JSValue result = jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value)); + LLINT_RETURN_WITH_PC_ADJUSTMENT(result, pc[4].u.operand); } } LLINT_THROW(createInvalidParamError(exec, "instanceof", baseVal)); diff --git a/runtime/JSString.cpp b/runtime/JSString.cpp index 86704d7..6f0b09d 100644 --- a/runtime/JSString.cpp +++ b/runtime/JSString.cpp @@ -40,6 +40,7 @@ void JSRopeString::RopeBuilder::expand() { ASSERT(m_index == JSRopeString::s_maxInternalRopeLength); JSString* jsString = m_jsString; + RELEASE_ASSERT(jsString); m_jsString = jsStringBuilder(&m_vm); m_index = 0; append(jsString); diff --git a/runtime/JSString.h b/runtime/JSString.h index 855de97..d913aff 100644 --- a/runtime/JSString.h +++ b/runtime/JSString.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -121,7 +121,8 @@ public: static JSString* create(VM& vm, PassRefPtr value) { ASSERT(value); - size_t length = value->length(); + int32_t length = value->length(); + RELEASE_ASSERT(length >= 0); size_t cost = value->cost(); JSString* newString = new (NotNull, allocateCell(vm.heap)) JSString(vm, value); newString->finishCreation(vm, length, cost); @@ -226,15 +227,21 @@ class JSRopeString : public JSString { { } - void append(JSString* jsString) + bool append(JSString* jsString) { if (m_index == JSRopeString::s_maxInternalRopeLength) expand(); + if (static_cast(m_jsString->length() + jsString->length()) < 0) { + m_jsString = nullptr; + return false; + } m_jsString->append(m_vm, m_index++, jsString); + return true; } JSRopeString* release() { + RELEASE_ASSERT(m_jsString); JSRopeString* tmp = m_jsString; m_jsString = 0; return tmp; @@ -284,6 +291,7 @@ private: { m_fibers[index].set(vm, this, jsString); m_length += jsString->m_length; + RELEASE_ASSERT(static_cast(m_length) >= 0); setIs8Bit(is8Bit() && jsString->is8Bit()); } diff --git a/runtime/Operations.h b/runtime/Operations.h index 14557c7..95bd9c0 100644 --- a/runtime/Operations.h +++ b/runtime/Operations.h @@ -41,13 +41,13 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) { VM& vm = exec->vm(); - unsigned length1 = s1->length(); + int32_t length1 = s1->length(); if (!length1) return s2; - unsigned length2 = s2->length(); + int32_t length2 = s2->length(); if (!length2) return s1; - if ((length1 + length2) < length1) + if (sumOverflows(length1, length2)) return throwOutOfMemoryError(exec); return JSRopeString::create(vm, s1, s2); @@ -57,9 +57,13 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& { VM* vm = &exec->vm(); - unsigned length1 = u1.length(); - unsigned length2 = u2.length(); - unsigned length3 = u3.length(); + int32_t length1 = u1.length(); + int32_t length2 = u2.length(); + int32_t length3 = u3.length(); + + if (length1 < 0 || length2 < 0 || length3 < 0) + return throwOutOfMemoryError(exec); + if (!length1) return jsString(exec, jsString(vm, u2), jsString(vm, u3)); if (!length2) @@ -67,9 +71,7 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, const String& u1, const String& if (!length3) return jsString(exec, jsString(vm, u1), jsString(vm, u2)); - if ((length1 + length2) < length1) - return throwOutOfMemoryError(exec); - if ((length1 + length2 + length3) < length3) + if (sumOverflows(length1, length2, length3)) return throwOutOfMemoryError(exec); return JSRopeString::create(exec->vm(), jsString(vm, u1), jsString(vm, u2), jsString(vm, u3)); @@ -80,15 +82,10 @@ ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned coun VM* vm = &exec->vm(); JSRopeString::RopeBuilder ropeBuilder(*vm); - unsigned oldLength = 0; - for (unsigned i = 0; i < count; ++i) { JSValue v = strings[i].jsValue(); - ropeBuilder.append(v.toString(exec)); - - if (ropeBuilder.length() < oldLength) // True for overflow + if (!ropeBuilder.append(v.toString(exec))) return throwOutOfMemoryError(exec); - oldLength = ropeBuilder.length(); } return ropeBuilder.release(); @@ -100,15 +97,10 @@ ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue) JSRopeString::RopeBuilder ropeBuilder(*vm); ropeBuilder.append(thisValue.toString(exec)); - unsigned oldLength = 0; - for (unsigned i = 0; i < exec->argumentCount(); ++i) { JSValue v = exec->argument(i); - ropeBuilder.append(v.toString(exec)); - - if (ropeBuilder.length() < oldLength) // True for overflow + if (!ropeBuilder.append(v.toString(exec))) return throwOutOfMemoryError(exec); - oldLength = ropeBuilder.length(); } return ropeBuilder.release(); diff --git a/runtime/StringPrototype.cpp b/runtime/StringPrototype.cpp index c422fd1..2e9baba 100644 --- a/runtime/StringPrototype.cpp +++ b/runtime/StringPrototype.cpp @@ -761,6 +761,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec) else { unsigned pos; int len = s.length(); + RELEASE_ASSERT(len >= 0); if (a1.isUInt32()) pos = std::min(a1.asUInt32(), len); else { @@ -904,6 +905,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec) return throwVMTypeError(exec); String s = thisValue.toString(exec)->value(exec); int len = s.length(); + RELEASE_ASSERT(len >= 0); JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); @@ -1216,6 +1218,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec) JSValue a0 = exec->argument(0); JSValue a1 = exec->argument(1); int len = jsString->length(); + RELEASE_ASSERT(len >= 0); double start = a0.toNumber(exec); double end; @@ -1253,6 +1256,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec) int sSize = s.length(); if (!sSize) return JSValue::encode(sVal); + RELEASE_ASSERT(sSize >= 0); StringImpl* ourImpl = s.impl(); RefPtr lower = ourImpl->lower(); diff --git a/tests/stress/make-large-string-jit-strcat.js b/tests/stress/make-large-string-jit-strcat.js new file mode 100644 index 0000000..a6aeb1d --- /dev/null +++ b/tests/stress/make-large-string-jit-strcat.js @@ -0,0 +1,24 @@ +// Like make-large-string-jit.js, but tests MakeRope with three arguments and op_strcat +// in the DFG and FTL JITs. + +var s = "s"; + +function foo(a, b) { + return "t" + a + b; +} + +noInline(foo); + +for (var i = 0; i < 100000; ++i) + foo("a", "b"); + +try { + for (var i = 0; i < 31; ++i) + s = foo(s, s); + print("Should not have gotten here."); + print("String length: " + s.length); + throw "Should not have gotten here."; +} catch (e) { + if (e.message != "Out of memory") + throw "Wrong error: " + e; +} diff --git a/tests/stress/make-large-string-jit.js b/tests/stress/make-large-string-jit.js new file mode 100644 index 0000000..8ee8847 --- /dev/null +++ b/tests/stress/make-large-string-jit.js @@ -0,0 +1,23 @@ +// Like make-large-string.js, but tests MakeRope with two arguments in the DFG and FTL JITs. + +var s = "s"; + +function foo(a, b) { + return a + b; +} + +noInline(foo); + +for (var i = 0; i < 100000; ++i) + foo("a", "b"); + +try { + for (var i = 0; i < 31; ++i) + s = foo(s, s); + print("Should not have gotten here."); + print("String length: " + s.length); + throw "Should not have gotten here."; +} catch (e) { + if (e.message != "Out of memory") + throw "Wrong error: " + e; +} diff --git a/tests/stress/make-large-string-strcat.js b/tests/stress/make-large-string-strcat.js new file mode 100644 index 0000000..f101228 --- /dev/null +++ b/tests/stress/make-large-string-strcat.js @@ -0,0 +1,12 @@ +var s = "s"; + +try { + for (var i = 0; i < 31; ++i) + s = "t" + s + s; + print("Should not have gotten here."); + print("String length: " + s.length); + throw "Should not have gotten here."; +} catch (e) { + if (e.message != "Out of memory") + throw "Wrong error: " + e; +} diff --git a/tests/stress/make-large-string.js b/tests/stress/make-large-string.js new file mode 100644 index 0000000..c3ad773 --- /dev/null +++ b/tests/stress/make-large-string.js @@ -0,0 +1,12 @@ +var s = "s"; + +try { + for (var i = 0; i < 31; ++i) + s = s + s; + print("Should not have gotten here."); + print("String length: " + s.length); + throw "Should not have gotten here."; +} catch (e) { + if (e.message != "Out of memory") + throw "Wrong error: " + e; +}