From 2781608a34eacc32f9262e2304a534648235be6b Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 9 Oct 2018 16:19:41 -0700 Subject: [PATCH 01/10] CVE-2018-8556 --- lib/Backend/GlobOptBailOut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Backend/GlobOptBailOut.cpp b/lib/Backend/GlobOptBailOut.cpp index 5a20d2b3337..c27a7af7863 100644 --- a/lib/Backend/GlobOptBailOut.cpp +++ b/lib/Backend/GlobOptBailOut.cpp @@ -1306,7 +1306,7 @@ GlobOpt::MayNeedBailOnImplicitCall(IR::Instr const * instr, Value const * src1Va return !( baseValueType.IsString() || - (baseValueType.IsAnyArray() && baseValueType.GetObjectType() != ObjectType::ObjectWithArray) || + baseValueType.IsArray() || (instr->HasBailOutInfo() && instr->GetBailOutKindNoBits() == IR::BailOutOnIrregularLength) // guarantees no implicit calls ); } From e73f2fff33c299934df28f2fc87d41aa9e149c50 Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 9 Oct 2018 16:37:02 -0700 Subject: [PATCH 02/10] CVE-2018-8557 --- lib/Backend/GlobOptFields.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/Backend/GlobOptFields.cpp b/lib/Backend/GlobOptFields.cpp index dba367cf3f9..85c7fb35ac7 100644 --- a/lib/Backend/GlobOptFields.cpp +++ b/lib/Backend/GlobOptFields.cpp @@ -1900,20 +1900,8 @@ GlobOpt::UpdateObjPtrValueType(IR::Opnd * opnd, IR::Instr * instr) switch (typeId) { default: - if (typeId > Js::TypeIds_LastStaticType) - { - Assert(typeId != Js::TypeIds_Proxy); - if (objValueType.IsLikelyArrayOrObjectWithArray()) - { - // If we have likely object with array before, we can't make it definite object with array - // since we have only proved that it is an object. - // Keep the likely array or object with array. - } - else - { - newValueType = ValueType::GetObject(ObjectType::Object); - } - } + // Can't mark as definite object because it may actually be object-with-array. + // Consider: a value type that subsumes object, array, and object-with-array. break; case Js::TypeIds_NativeIntArray: case Js::TypeIds_NativeFloatArray: From ef75eace57c0754428699485f10970ca0fb7a54d Mon Sep 17 00:00:00 2001 From: Seth Brenith Date: Fri, 28 Sep 2018 15:19:41 +0000 Subject: [PATCH 03/10] CVE-2018-8543 --- lib/Backend/IRBuilder.cpp | 22 +++++++++++++++++++--- lib/Backend/Inline.cpp | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/Backend/IRBuilder.cpp b/lib/Backend/IRBuilder.cpp index 733d37fee0b..f3edafe3a27 100644 --- a/lib/Backend/IRBuilder.cpp +++ b/lib/Backend/IRBuilder.cpp @@ -3749,7 +3749,7 @@ IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot r IR::Opnd* IRBuilder::GetEnvironmentOperand(uint32 offset) { - SymID symID; + StackSym* sym = nullptr; // The byte code doesn't refer directly to a closure environment. Get the implicit one // that's pointed to by the function body. if (m_func->DoStackFrameDisplay() && m_func->GetLocalFrameDisplaySym()) @@ -3760,19 +3760,35 @@ IRBuilder::GetEnvironmentOperand(uint32 offset) this->AddInstr( IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func), offset); - symID = regOpnd->m_sym->m_id; + sym = regOpnd->m_sym; } else { + SymID symID; symID = this->GetEnvRegForInnerFrameDisplay(); Assert(symID != Js::Constants::NoRegister); if (IsLoopBody() && !RegIsConstant(symID)) { this->EnsureLoopBodyLoadSlot(symID); } + + if (m_func->DoStackNestedFunc() && symID == GetEnvReg()) + { + // Environment is not guaranteed constant during this function because it could become boxed during execution, + // so load the environment every time you need it. + IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func); + this->AddInstr( + IR::Instr::New(Js::OpCode::LdEnv, regOpnd, m_func), + offset); + sym = regOpnd->m_sym; + } + else + { + sym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func); + } } - return IR::RegOpnd::New(StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func), TyVar, m_func); + return IR::RegOpnd::New(sym, TyVar, m_func); } template diff --git a/lib/Backend/Inline.cpp b/lib/Backend/Inline.cpp index 695bf7b62b4..b185ad83aea 100644 --- a/lib/Backend/Inline.cpp +++ b/lib/Backend/Inline.cpp @@ -5146,6 +5146,10 @@ Inline::MapFormals(Func *inlinee, else { instr->SetSrc1(funcObjOpnd); + + // This usage doesn't correspond with any byte code register, since interpreter stack frames + // get their function reference via this->function rather than from a register. + instr->GetSrc1()->SetIsJITOptimizedReg(true); } } else From 3bee8f018e15c803d87d8b2981d0522f6d58ecac Mon Sep 17 00:00:00 2001 From: Meghana Gupta Date: Mon, 15 Oct 2018 12:06:31 -0700 Subject: [PATCH 04/10] CVE-2018-8541 --- .../Language/InterpreterStackFrame.cpp | 4 + .../Language/JavascriptExceptionOperators.cpp | 304 ++++++++++-------- 2 files changed, 170 insertions(+), 138 deletions(-) diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp index bd0d8a69df1..a8ad0ffc1b7 100644 --- a/lib/Runtime/Language/InterpreterStackFrame.cpp +++ b/lib/Runtime/Language/InterpreterStackFrame.cpp @@ -6727,6 +6727,10 @@ namespace Js // Finally exited with LeaveNull, We don't throw for early returns if (finallyEndOffset == 0 && exceptionObj) { + if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) + { + JavascriptExceptionOperators::WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); + } JavascriptExceptionOperators::DoThrow(const_cast(exceptionObj), scriptContext); } if (finallyEndOffset != 0) diff --git a/lib/Runtime/Language/JavascriptExceptionOperators.cpp b/lib/Runtime/Language/JavascriptExceptionOperators.cpp index e8d09238320..4207cc1f430 100644 --- a/lib/Runtime/Language/JavascriptExceptionOperators.cpp +++ b/lib/Runtime/Language/JavascriptExceptionOperators.cpp @@ -190,19 +190,23 @@ namespace Js { void *tryContinuation = nullptr; JavascriptExceptionObject *exception = nullptr; + void *tryHandlerAddrOfReturnAddr = nullptr; Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)frame + hasBailedOutOffset)); PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize); - - try - { - tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize); - } - catch (const Js::JavascriptException& err) { - exception = err.GetAndClear(); + void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + try + { + tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize); + } + catch (const Js::JavascriptException& err) + { + exception = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); + } } - if (exception) { // Clone static exception object early in case finally block overwrites it @@ -212,19 +216,9 @@ namespace Js if (exception) { #if ENABLE_NATIVE_CODEGEN - if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) - { - if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); - } - } - else + if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) { - if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, frame); - } + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); } #endif bool hasBailedOut = *(bool*)((char*)frame + hasBailedOutOffset); // stack offsets are negative @@ -251,21 +245,31 @@ namespace Js void *tryContinuation = nullptr; void *finallyContinuation = nullptr; JavascriptExceptionObject *exception = nullptr; + void *tryHandlerAddrOfReturnAddr = nullptr; PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + spillSize + argsSize); - try - { - tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize); - } - catch (const Js::JavascriptException& err) { - exception = err.GetAndClear(); + void * addrOfReturnAddr = (void*)((char*)frame + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + try + { + tryContinuation = amd64_CallWithFakeFrame(tryAddr, frame, spillSize, argsSize); + } + catch (const Js::JavascriptException& err) + { + exception = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); + } } - if (exception) { // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); + + if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); + } } finallyContinuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize); @@ -276,6 +280,10 @@ namespace Js if (exception) { + if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); + } JavascriptExceptionOperators::DoThrow(exception, scriptContext); } @@ -365,44 +373,40 @@ namespace Js int hasBailedOutOffset, ScriptContext *scriptContext) { - void *tryContinuation = nullptr; - JavascriptExceptionObject *exception = nullptr; + void *tryContinuation = nullptr; + JavascriptExceptionObject *exception = nullptr; + void *tryHandlerAddrOfReturnAddr = nullptr; + Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)localsPtr + hasBailedOutOffset)); PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize); - try { + void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + try + { #if defined(_M_ARM) tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); #elif defined(_M_ARM64) tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); #endif - } - catch (const Js::JavascriptException& err) - { - exception = err.GetAndClear(); - } - - if (exception) - { -#if ENABLE_NATIVE_CODEGEN - if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) - { - if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); - } } - else + catch (const Js::JavascriptException& err) { - if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr); - } + exception = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); } -#endif + } + if (exception) + { // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); + + if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); + } + bool hasBailedOut = *(bool*)((char*)localsPtr + hasBailedOutOffset); // stack offsets are sp relative if (hasBailedOut) { @@ -437,26 +441,36 @@ namespace Js void *tryContinuation = nullptr; void *finallyContinuation = nullptr; JavascriptExceptionObject *exception = nullptr; + void *tryHandlerAddrOfReturnAddr = nullptr; PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout + argsSize); - - try { + void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + + try + { #if defined(_M_ARM) - tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); + tryContinuation = arm_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); #elif defined(_M_ARM64) - tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); + tryContinuation = arm64_CallEhFrame(tryAddr, framePtr, localsPtr, argsSize); #endif + } + catch (const Js::JavascriptException& err) + { + exception = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); + } } - catch (const Js::JavascriptException& err) - { - exception = err.GetAndClear(); - } - if (exception) { // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); + + if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); + } } #if defined(_M_ARM) @@ -472,6 +486,10 @@ namespace Js if (exception) { + if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); + } JavascriptExceptionOperators::DoThrow(exception, scriptContext); } @@ -647,21 +665,24 @@ namespace Js { Js::JavascriptExceptionObject* pExceptionObject = NULL; void* continuationAddr = NULL; + void* tryHandlerAddrOfReturnAddr = nullptr; Js::JavascriptExceptionOperators::HasBailedOutPtrStack hasBailedOutPtrStack(scriptContext, (bool*)((char*)framePtr + hasBailedOutOffset)); PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout); - - try { - // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function - // that may throw. The current workaround is to add the following dummy throw to prevent this optimization. - // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below). - // In order to circumvent that we are throwing OutOfMemory. - if (!tryAddr) + void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + try { - Assert(false); - ThrowOutOfMemory(scriptContext); - } + // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function + // that may throw. The current workaround is to add the following dummy throw to prevent this optimization. + // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below). + // In order to circumvent that we are throwing OutOfMemory. + if (!tryAddr) + { + Assert(false); + ThrowOutOfMemory(scriptContext); + } #ifdef _M_IX86 void *savedEsp; @@ -711,28 +732,19 @@ namespace Js #else AssertMsg(FALSE, "Unsupported native try-finally handler"); #endif + } + catch (const Js::JavascriptException& err) + { + pExceptionObject = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); + } } - catch(const Js::JavascriptException& err) - { - pExceptionObject = err.GetAndClear(); - } - if (pExceptionObject) { #if ENABLE_NATIVE_CODEGEN - if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) - { - if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); - } - } - else + if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction()) { - if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction()) - { - WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, framePtr); - } + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); } #endif // Clone static exception object early in case finally block overwrites it @@ -817,79 +829,91 @@ namespace Js { Js::JavascriptExceptionObject* pExceptionObject = NULL; void* continuationAddr = NULL; + void * tryHandlerAddrOfReturnAddr = nullptr; PROBE_STACK(scriptContext, Constants::MinStackJitEHBailout); - - try { - // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function - // that may throw. The current workaround is to add the following dummy throw to prevent this optimization. - // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below). - // In order to circumvent that we are throwing OutOfMemory. - if (!tryAddr) + void * addrOfReturnAddr = (void*)((char*)framePtr + sizeof(char*)); + Js::JavascriptExceptionOperators::TryHandlerAddrOfReturnAddrStack tryHandlerAddrOfReturnAddrStack(scriptContext, addrOfReturnAddr); + + try { - Assert(false); - ThrowOutOfMemory(scriptContext); - } + // Bug in compiler optimizer: try-catch can be optimized away if the try block contains __asm calls into function + // that may throw. The current workaround is to add the following dummy throw to prevent this optimization. + // It seems like compiler got smart and still optimizes if the exception is not JavascriptExceptionObject (see catch handler below). + // In order to circumvent that we are throwing OutOfMemory. + if (!tryAddr) + { + Assert(false); + ThrowOutOfMemory(scriptContext); + } #ifdef _M_IX86 - void *savedEsp; - __asm - { - // Save and restore the callee-saved registers around the call. - // TODO: track register kills by region and generate per-region prologs and epilogs - push esi - push edi - push ebx + void *savedEsp; + __asm + { + // Save and restore the callee-saved registers around the call. + // TODO: track register kills by region and generate per-region prologs and epilogs + push esi + push edi + push ebx - // 8-byte align frame to improve floating point perf of our JIT'd code. - // Save ESP - mov ecx, esp - mov savedEsp, ecx - and esp, -8 + // 8-byte align frame to improve floating point perf of our JIT'd code. + // Save ESP + mov ecx, esp + mov savedEsp, ecx + and esp, -8 - // Set up the call target, save the current frame ptr, and adjust the frame to access - // locals in native code. - mov eax, tryAddr + // Set up the call target, save the current frame ptr, and adjust the frame to access + // locals in native code. + mov eax, tryAddr #if 0 && defined(_CONTROL_FLOW_GUARD) - // verify that the call target is valid - mov ebx, eax; save call target - mov ecx, eax - call[__guard_check_icall_fptr] - mov eax, ebx; restore call target + // verify that the call target is valid + mov ebx, eax; save call target + mov ecx, eax + call[__guard_check_icall_fptr] + mov eax, ebx; restore call target #endif - push ebp - mov ebp, framePtr - call eax - pop ebp + push ebp + mov ebp, framePtr + call eax + pop ebp - // The native code gives us the address where execution should continue on exit - // from the region. - mov continuationAddr, eax + // The native code gives us the address where execution should continue on exit + // from the region. + mov continuationAddr, eax - // Restore ESP - mov ecx, savedEsp - mov esp, ecx + // Restore ESP + mov ecx, savedEsp + mov esp, ecx - pop ebx - pop edi - pop esi - } + pop ebx + pop edi + pop esi + } #else - AssertMsg(FALSE, "Unsupported native try-finally handler"); + AssertMsg(FALSE, "Unsupported native try-finally handler"); #endif + } + catch (const Js::JavascriptException& err) + { + pExceptionObject = err.GetAndClear(); + tryHandlerAddrOfReturnAddr = scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr(); + } } - catch (const Js::JavascriptException& err) - { - pExceptionObject = err.GetAndClear(); - } - if (pExceptionObject) { // Clone static exception object early in case finally block overwrites it pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext); + +#if ENABLE_NATIVE_CODEGEN + if (pExceptionObject->GetExceptionContext() && pExceptionObject->GetExceptionContext()->ThrowingFunction()) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); + } +#endif } void* newContinuationAddr = NULL; @@ -952,6 +976,10 @@ namespace Js if (pExceptionObject) { + if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) + { + WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); + } JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext); } From 6199b5e19a61744f5d2357bbbaf1b50dd284c4a6 Mon Sep 17 00:00:00 2001 From: Taylor Woll Date: Mon, 17 Sep 2018 22:58:33 +0000 Subject: [PATCH 05/10] CVE-2018-8551 --- lib/Parser/Scan.cpp | 17 ++++++++++--- lib/Parser/Scan.h | 2 +- test/Bugs/bug_5585.js | 55 +++++++++++++++++++++++++++++++++++++++++++ test/Bugs/rlexe.xml | 6 +++++ 4 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 test/Bugs/bug_5585.js diff --git a/lib/Parser/Scan.cpp b/lib/Parser/Scan.cpp index 3aebff8d10d..a1bb126a387 100644 --- a/lib/Parser/Scan.cpp +++ b/lib/Parser/Scan.cpp @@ -193,13 +193,16 @@ void Scanner::PrepareForBackgroundParse(Js::ScriptContext *scrip // This is used to determine a length of BSTR, which can't contain a NUL character. //----------------------------------------------------------------------------- template -charcount_t Scanner::LineLength(EncodedCharPtr first, EncodedCharPtr last) +charcount_t Scanner::LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb) { + Assert(cb != nullptr); + charcount_t result = 0; EncodedCharPtr p = first; for (;;) { + EncodedCharPtr prev = p; switch( this->template ReadFull(p, last) ) { case kchNWL: // _C_NWL @@ -207,6 +210,13 @@ charcount_t Scanner::LineLength(EncodedCharPtr first, EncodedCha case kchLS: case kchPS: case kchNUL: // _C_NUL + // p is now advanced past the line terminator character. + // We need to know the number of bytes making up the line, not including the line terminator character. + // To avoid subtracting a variable number of bytes because the line terminator characters are different + // number of bytes long (plus there may be multiple valid encodings for these characters) just keep + // track of the first byte of the line terminator character in prev. + Assert(prev >= first); + *cb = prev - first; return result; } result++; @@ -2313,10 +2323,11 @@ HRESULT Scanner::SysAllocErrorLine(int32 ichMinLine, __out BSTR* typename EncodingPolicy::EncodedCharPtr pStart = static_cast(ichMinLine) == IchMinLine() ? m_pchMinLine : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, ichMinLine); // Determine the length by scanning for the next newline - charcount_t cch = LineLength(pStart, m_pchLast); + size_t cb = 0; + charcount_t cch = LineLength(pStart, m_pchLast, &cb); Assert(cch <= LONG_MAX); - typename EncodingPolicy::EncodedCharPtr pEnd = static_cast(ichMinLine) == IchMinLine() ? m_pchMinLine + cch : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch); + typename EncodingPolicy::EncodedCharPtr pEnd = static_cast(ichMinLine) == IchMinLine() ? m_pchMinLine + cb : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch); *pbstrLine = SysAllocStringLen(NULL, cch); if (!*pbstrLine) diff --git a/lib/Parser/Scan.h b/lib/Parser/Scan.h index ae735f228d9..b34e163b374 100644 --- a/lib/Parser/Scan.h +++ b/lib/Parser/Scan.h @@ -780,7 +780,7 @@ class Scanner : public IScanner, public EncodingPolicy void ScanNewLine(uint ch); void NotifyScannedNewLine(); - charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last); + charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb); tokens ScanIdentifier(bool identifyKwds, EncodedCharPtr *pp); BOOL FastIdentifierContinue(EncodedCharPtr&p, EncodedCharPtr last); diff --git a/test/Bugs/bug_5585.js b/test/Bugs/bug_5585.js new file mode 100644 index 00000000000..afa523ec63d --- /dev/null +++ b/test/Bugs/bug_5585.js @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js"); + +let line = 't("摩"2)'; +let module_name = 'temp.js'; +WScript.RegisterModuleSource(module_name, line); + +var tests = [ + { + name: "Syntax error thrown parsing dynamic module", + body: function () { + let source = `import(module_name) + .then(v => { + assert.fail("Parsing this module should not succeed"); + }, e => { + assert.areEqual(line, e.source, "Source line causing compile error"); + }).catch(e => { + console.log('fail: ' + e); + throw e; + });` + + testRunner.LoadModule(source, 'samethread', true, false); + } + }, + { + name: "Syntax error thrown parsing module code", + body: function () { + try { + WScript.LoadScriptFile(module_name, 'module'); + assert.fail("Parsing this module should not succeed"); + } catch(e) { + assert.areEqual(line, e.source, "Source line causing compile error"); + } + } + }, + { + name: "Error line which contains multi-byte UTF-8 sequence which is an end-of-line character", + body: function () { + WScript.RegisterModuleSource('temp2.js', 't("\u2028"2)'); + + try { + WScript.LoadScriptFile('temp2.js', 'module'); + assert.fail("Parsing this module should not succeed"); + } catch(e) { + assert.areEqual('t("', e.source, "Source line causing compile error"); + } + } + } +]; + +testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" }); diff --git a/test/Bugs/rlexe.xml b/test/Bugs/rlexe.xml index 6f951bdd6cf..60e5d2eb838 100644 --- a/test/Bugs/rlexe.xml +++ b/test/Bugs/rlexe.xml @@ -530,4 +530,10 @@ exclude_jshost + + + bug_5585.js + -esdynamicimport -mutehosterrormsg -args summary -endargs + + From 8943e332ea5c8d7bf7d89301b30a1412e318ae97 Mon Sep 17 00:00:00 2001 From: Akrosh Gandhi Date: Mon, 22 Oct 2018 15:25:05 -0700 Subject: [PATCH 06/10] CVE-2018-8555 --- lib/Backend/GlobOpt.cpp | 2 ++ lib/Backend/GlobOptExpr.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp index 6a1cc9de1a9..3087b08d586 100644 --- a/lib/Backend/GlobOpt.cpp +++ b/lib/Backend/GlobOpt.cpp @@ -13375,6 +13375,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr) case IR::HelperArray_Shift: case IR::HelperArray_Splice: case IR::HelperArray_Unshift: + case IR::HelperArray_Concat: kills.SetKillsArrayHeadSegments(); kills.SetKillsArrayHeadSegmentLengths(); break; @@ -13404,6 +13405,7 @@ GlobOpt::CheckJsArrayKills(IR::Instr *const instr) //case IR::HelperArray_Sort: case IR::HelperArray_Splice: case IR::HelperArray_Unshift: + case IR::HelperArray_Concat: kills.SetKillsNativeArrays(); break; } diff --git a/lib/Backend/GlobOptExpr.cpp b/lib/Backend/GlobOptExpr.cpp index 2af0dbd129a..cc1d4ff0820 100644 --- a/lib/Backend/GlobOptExpr.cpp +++ b/lib/Backend/GlobOptExpr.cpp @@ -844,6 +844,7 @@ GlobOpt::ProcessArrayValueKills(IR::Instr *instr) case IR::HelperArray_Shift: case IR::HelperArray_Unshift: case IR::HelperArray_Splice: + case IR::HelperArray_Concat: this->currentBlock->globOptData.liveArrayValues->ClearAll(); break; } From 334471b7254c1c093deb413bac0472974e6f9181 Mon Sep 17 00:00:00 2001 From: Rajat Dua Date: Tue, 23 Oct 2018 16:25:13 -0700 Subject: [PATCH 07/10] CVE-2018-8542 --- lib/Runtime/Language/ValueType.cpp | 38 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/Runtime/Language/ValueType.cpp b/lib/Runtime/Language/ValueType.cpp index 4e66e0bd40e..fb264cbe1e6 100644 --- a/lib/Runtime/Language/ValueType.cpp +++ b/lib/Runtime/Language/ValueType.cpp @@ -1055,6 +1055,10 @@ ValueType ValueType::MergeWithObject(const ValueType other) const { // Any two different specific object types (excludes UninitializedObject and Object, which don't indicate any // specific type of object) merge to Object since the resulting type is not guaranteed to indicate any specific type + if (IsArrayOrObjectWithArray() || other.IsArrayOrObjectWithArray()) + { + return Verify(GetObject(ObjectType::Object).ToLikely()); + } merged.SetObjectType(ObjectType::Object); return Verify(merged); } @@ -1945,13 +1949,18 @@ void ValueType::RunUnitTests() )); if(!( - t0.IsObject() && t1.IsObject() && // both are objects + t0.IsObject() && t1.IsObject() && // both are objects ( - t0.GetObjectType() == ObjectType::UninitializedObject || - t1.GetObjectType() == ObjectType::UninitializedObject - ) && // one has an uninitialized object type - (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object) // one has a specific object type - )) // then the resulting object type is not guaranteed + ( + ( + t0.GetObjectType() == ObjectType::UninitializedObject || + t1.GetObjectType() == ObjectType::UninitializedObject + ) && // one has an uninitialized object type + (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object) // one has a specific object type + ) || + (t0.IsArrayOrObjectWithArray() || t1.IsArrayOrObjectWithArray()) // or one was an array or an object with array + ) + )) // then the resulting object type is not guaranteed { Assert(m.IsNotInt() == (t0.IsNotInt() && t1.IsNotInt())); } @@ -1990,13 +1999,18 @@ void ValueType::RunUnitTests() Assert(m.IsLikelyString() == (t0.IsLikelyString() && t1.IsLikelyString())); if(!( - t0.IsObject() && t1.IsObject() && // both are objects + t0.IsObject() && t1.IsObject() && // both are objects ( - t0.GetObjectType() == ObjectType::UninitializedObject || - t1.GetObjectType() == ObjectType::UninitializedObject - ) && // one has an uninitialized object type - (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object) // one has a specific object type - )) // then the resulting object type is not guaranteed + ( + ( + t0.GetObjectType() == ObjectType::UninitializedObject || + t1.GetObjectType() == ObjectType::UninitializedObject + ) && // one has an uninitialized object type + (t0.GetObjectType() > ObjectType::Object || t1.GetObjectType() > ObjectType::Object) // one has a specific object type + ) || + (t0.IsArrayOrObjectWithArray() || t1.IsArrayOrObjectWithArray()) // or one was an array or an object with array + ) + )) // then the resulting object type is not guaranteed { Assert(m.IsObject() == (t0.IsObject() && t1.IsObject())); } From c76da44c27fcf06ad5ac3ee6f8d45efb8d8bc04f Mon Sep 17 00:00:00 2001 From: Rajat Dua Date: Wed, 24 Oct 2018 12:10:11 -0700 Subject: [PATCH 08/10] CVE-2018-8588 --- lib/Backend/Lower.cpp | 39 ++++++++++------------ lib/Runtime/Library/JavascriptArray.cpp | 6 ++-- lib/Runtime/Library/JavascriptArray.inl | 6 ++++ lib/Runtime/Library/SparseArraySegment.h | 1 + lib/Runtime/Library/SparseArraySegment.inl | 6 ++++ lib/Runtime/RuntimeCommon.h | 3 ++ 6 files changed, 37 insertions(+), 24 deletions(-) diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp index 35247ae9f42..cb3efbe0efe 100644 --- a/lib/Backend/Lower.cpp +++ b/lib/Backend/Lower.cpp @@ -3765,13 +3765,11 @@ Lowerer::GenerateProfiledNewScArrayFastPath(IR::Instr *instr, Js::ArrayCallSiteI GenerateMemInit(dstOpnd, Js::JavascriptNativeFloatArray::GetOffsetOfWeakFuncRef(), IR::AddrOpnd::New(weakFuncRef, IR::AddrOpndKindDynamicFunctionBodyWeakRef, m_func), instr, isZeroed); // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit. uint const offsetStart = sizeof(Js::SparseArraySegmentBase); - uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem); - i = i * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem); - for (; i < missingItemCount; i++) + for (; i < size; i++) { GenerateMemInit( - headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem), - IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), + headOpnd, offsetStart + i * sizeof(double), + GetMissingItemOpndForAssignment(TyFloat64, m_func), instr, isZeroed); } } @@ -3788,7 +3786,7 @@ Lowerer::GenerateProfiledNewScArrayFastPath(IR::Instr *instr, Js::ArrayCallSiteI { GenerateMemInit( headOpnd, offsetStart + i * sizeof(Js::Var), - IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), + GetMissingItemOpndForAssignment(TyVar, m_func), instr, isZeroed); } } @@ -4111,12 +4109,11 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit. uint const offsetStart = sizeof(Js::SparseArraySegmentBase); - uint const missingItemCount = size * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem); - for (uint i = 0; i < missingItemCount; i++) + for (uint i = 0; i < size; i++) { GenerateMemInit( - headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem), - IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), + headOpnd, offsetStart + i * sizeof(double), + GetMissingItemOpndForAssignment(TyFloat64, m_func), instr, isZeroed); } } @@ -4126,9 +4123,9 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi headOpnd = GenerateArrayObjectsAlloc(instr, &size, arrayInfo, &isZeroed, isNoArgs); for (uint i = 0; i < size; i++) { - GenerateMemInit( + GenerateMemInit( headOpnd, offsetStart + i * sizeof(Js::Var), - IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), + GetMissingItemOpndForAssignment(TyVar, m_func), instr, isZeroed); } } @@ -4159,8 +4156,8 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi uint allocationBucketsCount = ArrayType::AllocationBucketsCount; uint(*allocationBuckets)[Js::JavascriptArray::AllocationBucketsInfoSize]; allocationBuckets = ArrayType::allocationBuckets; - uint sizeFactor = 1; - IRType missingItemType = (arrayInfo && arrayInfo->IsNativeIntArray()) ? IRType::TyInt32 : IRType::TyVar; + + IRType missingItemType = (arrayInfo ? arrayInfo->IsNativeIntArray() ? IRType::TyInt32 : arrayInfo->IsNativeFloatArray() ? IRType::TyFloat64 : IRType::TyVar : IRType::TyVar); IR::LabelInstr * arrayInitDone = IR::LabelInstr::New(Js::OpCode::Label, func); bool isNativeArray = arrayInfo && (arrayInfo->IsNativeIntArray() || arrayInfo->IsNativeFloatArray()); @@ -4172,9 +4169,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi } else if (arrayInfo && arrayInfo->IsNativeFloatArray()) { - // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit. - sizeFactor = sizeof(double) / sizeof(Js::JavascriptArray::MissingItem); - sizeOfElement = sizeof(Js::JavascriptArray::MissingItem); + sizeOfElement = sizeof(double); GenerateArrayInfoIsNativeFloatAndNotIntArrayTest(instr, arrayInfo, arrayInfoAddr, helperLabel); } else @@ -4204,7 +4199,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi for (uint8 i = 0;i < allocationBucketsCount;i++) { - missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor; + missingItemCount = allocationBuckets[i][Js::JavascriptArray::MissingElementsCountIndex]; if (i > 0) { @@ -4235,7 +4230,7 @@ Lowerer::GenerateProfiledNewScObjArrayFastPath(IR::Instr *instr, Js::ArrayCallSi // Ensure no. of missingItems written are same Assert(missingItemIndex == missingItemInitializedSoFar); // Ensure no. of missingItems match what present in allocationBuckets - Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex] * sizeFactor); + Assert(missingItemIndex == allocationBuckets[allocationBucketsCount - 1][Js::JavascriptArray::MissingElementsCountIndex]); instr->InsertBefore(arrayInitDone); @@ -4363,11 +4358,11 @@ Lowerer::GenerateProfiledNewScFloatArrayFastPath(IR::Instr *instr, Js::ArrayCall // Js::JavascriptArray::MissingItem is a Var, so it may be 32-bit or 64 bit. uint const offsetStart = sizeof(Js::SparseArraySegmentBase) + doubles->count * sizeof(double); - uint const missingItem = (size - doubles->count) * sizeof(double) / sizeof(Js::JavascriptArray::MissingItem); + uint const missingItem = (size - doubles->count); for (uint i = 0; i < missingItem; i++) { - GenerateMemInit(headOpnd, offsetStart + i * sizeof(Js::JavascriptArray::MissingItem), - IR::AddrOpnd::New(Js::JavascriptArray::MissingItem, IR::AddrOpndKindConstantAddress, m_func, true), instr, isHeadSegmentZeroed); + GenerateMemInit(headOpnd, offsetStart + i * sizeof(double), + GetMissingItemOpndForAssignment(TyFloat64, m_func), instr, isHeadSegmentZeroed); } // Skip pass the helper call IR::LabelInstr * doneLabel = IR::LabelInstr::New(Js::OpCode::Label, func); diff --git a/lib/Runtime/Library/JavascriptArray.cpp b/lib/Runtime/Library/JavascriptArray.cpp index ffed86868ab..4947798d7f0 100644 --- a/lib/Runtime/Library/JavascriptArray.cpp +++ b/lib/Runtime/Library/JavascriptArray.cpp @@ -28,7 +28,7 @@ using namespace Js; { 8, 0, 0 }, // allocate space for 8 elements for array of length 6,7,8 }; - const Var JavascriptArray::MissingItem = (Var)FloatMissingItemPattern; + const Var JavascriptArray::MissingItem = (Var)VarMissingItemPattern; #if defined(TARGET_64) const Var JavascriptArray::IntMissingItemVar = (Var)(((uint64)IntMissingItemPattern << 32) | (uint32)IntMissingItemPattern); @@ -2048,6 +2048,8 @@ using namespace Js; { ((SparseArraySegment*)seg)->elements[i] = JavascriptNumber::ToVar(ival, scriptContext); } + SparseArraySegment* newSeg = (SparseArraySegment*)seg; + newSeg->FillSegmentBuffer(seg->length, seg->size); } prevSeg = seg; } @@ -2243,7 +2245,7 @@ using namespace Js; } } } - if (seg == newSeg && shrinkFactor != 1) + if (seg == newSeg) { // Fill the remaining slots. newSeg->FillSegmentBuffer(i, seg->size); diff --git a/lib/Runtime/Library/JavascriptArray.inl b/lib/Runtime/Library/JavascriptArray.inl index 0f906e23be1..78de6803fd2 100644 --- a/lib/Runtime/Library/JavascriptArray.inl +++ b/lib/Runtime/Library/JavascriptArray.inl @@ -486,6 +486,8 @@ namespace Js template inline void JavascriptArray::DirectSetItemInLastUsedSegmentAt(const uint32 offset, const T newValue) { + Assert(!SparseArraySegment::IsMissingItem(&newValue)); + SparseArraySegment *const seg = (SparseArraySegment*)GetLastUsedSegment(); Assert(seg); Assert(offset < seg->size); @@ -526,6 +528,8 @@ namespace Js const T newValue, StElemInfo *const stElemInfo) { + Assert(!SparseArraySegment::IsMissingItem(&newValue)); + SparseArraySegment *const seg = SparseArraySegment::From(head); Assert(seg); Assert(offset < seg->size); @@ -1219,6 +1223,8 @@ SECOND_PASS: template void JavascriptArray::DirectSetItem_Full(uint32 itemIndex, T newValue) { + Assert(!SparseArraySegment::IsMissingItem(&newValue)); + DebugOnly(VerifyNotNeedMarshal(newValue)); this->EnsureHead(); AnalysisAssert(head); diff --git a/lib/Runtime/Library/SparseArraySegment.h b/lib/Runtime/Library/SparseArraySegment.h index 219ad532f81..8e0672d477f 100644 --- a/lib/Runtime/Library/SparseArraySegment.h +++ b/lib/Runtime/Library/SparseArraySegment.h @@ -147,6 +147,7 @@ namespace Js return JavascriptArray::MissingItem; } template<> Var SparseArraySegment::GetMissingItemVar(); + Var SparseArraySegment::GetMissingItemVar(); template<> inline bool SparseArraySegment::IsMissingItem(const double* value) diff --git a/lib/Runtime/Library/SparseArraySegment.inl b/lib/Runtime/Library/SparseArraySegment.inl index 669faea8943..8e0f1515db1 100644 --- a/lib/Runtime/Library/SparseArraySegment.inl +++ b/lib/Runtime/Library/SparseArraySegment.inl @@ -229,6 +229,12 @@ namespace Js return JavascriptArray::IntMissingItemVar; } + template<> + inline Var SparseArraySegment::GetMissingItemVar() + { + return (Var)FloatMissingItemPattern; + } + template void SparseArraySegment::FillSegmentBuffer(uint32 start, uint32 size) { diff --git a/lib/Runtime/RuntimeCommon.h b/lib/Runtime/RuntimeCommon.h index 484953244a8..da1b7aa327a 100644 --- a/lib/Runtime/RuntimeCommon.h +++ b/lib/Runtime/RuntimeCommon.h @@ -179,6 +179,9 @@ namespace Js #if FLOATVAR const uint64 FloatTag_Value = 0xFFFCull << 48; + const uint64 VarMissingItemPattern = 0x00040002FFF80002; // Float-tagged representation of FloatMissingItemPattern +#else + const int32 VarMissingItemPattern = 0xFFF80002; #endif const uint64 FloatMissingItemPattern = 0xFFF80002FFF80002; const int32 IntMissingItemPattern = 0xFFF80002; From 68e1e9d83b22b9dd8da9cf8b713f35a304fd48cb Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 13 Nov 2018 11:40:38 -0800 Subject: [PATCH 09/10] Fix OSX/Ubuntu builds --- lib/Runtime/Library/SparseArraySegment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Runtime/Library/SparseArraySegment.h b/lib/Runtime/Library/SparseArraySegment.h index 8e0672d477f..42edbc0fb39 100644 --- a/lib/Runtime/Library/SparseArraySegment.h +++ b/lib/Runtime/Library/SparseArraySegment.h @@ -147,7 +147,7 @@ namespace Js return JavascriptArray::MissingItem; } template<> Var SparseArraySegment::GetMissingItemVar(); - Var SparseArraySegment::GetMissingItemVar(); + template<> Var SparseArraySegment::GetMissingItemVar(); template<> inline bool SparseArraySegment::IsMissingItem(const double* value) From 0b6dc52ccd2d14b7faef60d9abd6a00274c48729 Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 13 Nov 2018 12:07:59 -0800 Subject: [PATCH 10/10] Fix NoJIT build --- lib/Runtime/Language/InterpreterStackFrame.cpp | 2 ++ .../Language/JavascriptExceptionOperators.cpp | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/Runtime/Language/InterpreterStackFrame.cpp b/lib/Runtime/Language/InterpreterStackFrame.cpp index a8ad0ffc1b7..27f527777ab 100644 --- a/lib/Runtime/Language/InterpreterStackFrame.cpp +++ b/lib/Runtime/Language/InterpreterStackFrame.cpp @@ -6727,10 +6727,12 @@ namespace Js // Finally exited with LeaveNull, We don't throw for early returns if (finallyEndOffset == 0 && exceptionObj) { +#if ENABLE_NATIVE_CODEGEN if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) { JavascriptExceptionOperators::WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); } +#endif JavascriptExceptionOperators::DoThrow(const_cast(exceptionObj), scriptContext); } if (finallyEndOffset != 0) diff --git a/lib/Runtime/Language/JavascriptExceptionOperators.cpp b/lib/Runtime/Language/JavascriptExceptionOperators.cpp index 4207cc1f430..2f64e7f8cd1 100644 --- a/lib/Runtime/Language/JavascriptExceptionOperators.cpp +++ b/lib/Runtime/Language/JavascriptExceptionOperators.cpp @@ -265,11 +265,12 @@ namespace Js { // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); - +#if ENABLE_NATIVE_CODEGEN if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); } +#endif } finallyContinuation = amd64_CallWithFakeFrame(finallyAddr, frame, spillSize, argsSize); @@ -280,10 +281,12 @@ namespace Js if (exception) { +#if ENABLE_NATIVE_CODEGEN if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); } +#endif JavascriptExceptionOperators::DoThrow(exception, scriptContext); } @@ -401,12 +404,12 @@ namespace Js { // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); - +#if ENABLE_NATIVE_CODEGEN if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); } - +#endif bool hasBailedOut = *(bool*)((char*)localsPtr + hasBailedOutOffset); // stack offsets are sp relative if (hasBailedOut) { @@ -467,10 +470,12 @@ namespace Js // Clone static exception object early in case finally block overwrites it exception = exception->CloneIfStaticExceptionObject(scriptContext); +#if ENABLE_NATIVE_CODEGEN if (exception->GetExceptionContext() && exception->GetExceptionContext()->ThrowingFunction()) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr /* start stackwalk from the current frame */, tryHandlerAddrOfReturnAddr); } +#endif } #if defined(_M_ARM) @@ -486,10 +491,12 @@ namespace Js if (exception) { +#if ENABLE_NATIVE_CODEGEN if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); } +#endif JavascriptExceptionOperators::DoThrow(exception, scriptContext); } @@ -976,10 +983,12 @@ namespace Js if (pExceptionObject) { +#if ENABLE_NATIVE_CODEGEN if (scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr() != nullptr) { WalkStackForCleaningUpInlineeInfo(scriptContext, nullptr, scriptContext->GetThreadContext()->GetTryHandlerAddrOfReturnAddr()); } +#endif JavascriptExceptionOperators::DoThrow(pExceptionObject, scriptContext); }