VYPR
High severityNVD Advisory· Published Mar 14, 2018· Updated Sep 17, 2024

CVE-2018-0934

CVE-2018-0934

Description

Chakra scripting engine memory corruption in Microsoft Edge and ChakraCore allows remote code execution via crafted web content.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Chakra scripting engine memory corruption in Microsoft Edge and ChakraCore allows remote code execution via crafted web content.

Vulnerability

A memory corruption vulnerability exists in the Chakra scripting engine, specifically in the JIT compiler's handling of stack-to-heap copies for JavaScript arrays. The flaw resides in JavascriptArray::BoxStackInstance and JavascriptStackWalker::GetJavascriptArgs functions, where an incomplete fix for a prior issue (MSRC-41913) left a code path that could be exploited. Affected versions include ChakraCore and Microsoft Edge on Windows 10 Gold, 1511, 1607, 1703, 1709, and Windows Server 2016 [1][2].

Exploitation

An attacker can host a malicious website and lure a victim to visit it using Microsoft Edge. The exploit leverages the Error constructor, which iterates over all functions and arguments in the call stack and invokes BoxStackInstance with deepCopy set to false. This causes a shallow copy of a stack-allocated array to be cached. On subsequent calls, the cached shallow copy is returned, leading to a use-after-free condition when the original stack object is freed [3]. No authentication or user interaction beyond browsing is required [4].

Impact

Successful exploitation allows remote code execution in the context of the current user. An attacker can gain the same user privileges, potentially leading to full system compromise if the user is an administrator [1][4].

Mitigation

Microsoft released security updates as part of the March 2018 Patch Tuesday (March 13, 2018). Users should apply the latest updates for affected Windows versions and ChakraCore. The fix is also available in the ChakraCore repository commit 6d0f5de [2]. No workarounds are available; updating is the only mitigation [1][4].

AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.8.21.8.2

Affected products

2
  • ghsa-coords
    Range: < 1.8.2
  • Microsoft Corporation/ChakraCore, Microsoft Edgev5
    Range: ChakraCore, Microsoft Windows 10 Gold, 1511, 1607, 1703, 1709, and Windows Server 2016.

Patches

1
6d0f5de1e033

[CVE-2018-0934] Chakra JIT - Incomplete fix for MSRC-41913 #2 - Google, Inc.

https://github.com/chakra-core/ChakraCoreThomas Moore (CHAKRA)Feb 10, 2018via ghsa
11 files changed · +90 121
  • lib/Backend/BailOut.cpp+4 1 modified
    @@ -1301,8 +1301,11 @@ BailOutRecord::BailOutInlinedHelper(Js::JavascriptCallStackLayout * layout, Bail
             InlineeFrameRecord* inlineeFrameRecord = entryPointInfo->FindInlineeFrame(returnAddress);
             if (inlineeFrameRecord)
             {
    +            // While bailing out, RestoreFrames should box all Vars on the stack. If there are multiple Vars pointing to the same
    +            // object, the cached version (that was previously boxed) will be reused to maintain pointer identity and correctness
    +            // after the transition to the interpreter.
                 InlinedFrameLayout* outerMostFrame = (InlinedFrameLayout *)(((uint8 *)Js::JavascriptCallStackLayout::ToFramePointer(layout)) - entryPointInfo->frameHeight);
    -            inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, false /* deepCopy */);
    +            inlineeFrameRecord->RestoreFrames(functionBody, outerMostFrame, layout, true /* boxArgs */);
             }
         }
     
    
  • lib/Backend/InlineeFrameInfo.cpp+15 9 modified
    @@ -199,14 +199,14 @@ void InlineeFrameRecord::Finalize(Func* inlinee, uint32 currentOffset)
         Assert(this->inlineDepth != 0);
     }
     
    -void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *inlinedFrame, Js::JavascriptCallStackLayout * layout, bool deepCopy) const
    +void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *inlinedFrame, Js::JavascriptCallStackLayout * layout, bool boxValues) const
     {
         Assert(this->inlineDepth != 0);
         Assert(inlineeStartOffset != 0);
     
         BAILOUT_VERBOSE_TRACE(functionBody, _u("Restore function object: "));
         // No deepCopy needed for just the function
    -    Js::Var varFunction = this->Restore(this->functionOffset, /*isFloat64*/ false, /*isInt32*/ false, layout, functionBody, /*deepCopy*/ false);
    +    Js::Var varFunction = this->Restore(this->functionOffset, /*isFloat64*/ false, /*isInt32*/ false, layout, functionBody, boxValues);
         Assert(Js::ScriptFunction::Is(varFunction));
     
         Js::ScriptFunction* function = Js::ScriptFunction::FromVar(varFunction);
    @@ -222,9 +222,9 @@ void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLay
     
             // Forward deepCopy flag for the arguments in case their data must be guaranteed
             // to have its own lifetime
    -        Js::Var var = this->Restore(this->argOffsets[i], isFloat64, isInt32, layout, functionBody, deepCopy);
    +        Js::Var var = this->Restore(this->argOffsets[i], isFloat64, isInt32, layout, functionBody, boxValues);
     #if DBG
    -        if (!Js::TaggedNumber::Is(var))
    +        if (boxValues && !Js::TaggedNumber::Is(var))
             {
                 Js::RecyclableObject *const recyclableObject = Js::RecyclableObject::FromVar(var);
                 Assert(!ThreadContext::IsOnStack(recyclableObject));
    @@ -236,7 +236,10 @@ void InlineeFrameRecord::Restore(Js::FunctionBody* functionBody, InlinedFrameLay
         BAILOUT_FLUSH(functionBody);
     }
     
    -void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack, bool deepCopy)
    +// Note: the boxValues parameter should be true when this is called from a Bailout codepath to ensure that multiple vars to
    +// the same object reuse the cached value during the transition to the interpreter.
    +// Otherwise, this parameter should be false as the values are not required to be moved to the heap to restore the frame.
    +void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostFrame, Js::JavascriptCallStackLayout* callstack, bool boxValues)
     {
         InlineeFrameRecord* innerMostRecord = this;
         class AutoReverse
    @@ -274,7 +277,7 @@ void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFr
     
         while (currentRecord)
         {
    -        currentRecord->Restore(functionBody, currentFrame, callstack, deepCopy);
    +        currentRecord->Restore(functionBody, currentFrame, callstack, boxValues);
             currentRecord = currentRecord->parent;
             currentFrame = currentFrame->Next();
         }
    @@ -283,10 +286,10 @@ void InlineeFrameRecord::RestoreFrames(Js::FunctionBody* functionBody, InlinedFr
         currentFrame->callInfo.Count = 0;
     }
     
    -Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool deepCopy) const
    +Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool boxValue) const
     {
         Js::Var value;
    -    bool boxStackInstance = true;
    +    bool boxStackInstance = boxValue;
         double dblValue;
         if (offset >= 0)
         {
    @@ -324,8 +327,11 @@ Js::Var InlineeFrameRecord::Restore(int offset, bool isFloat64, bool isInt32, Js
             BAILOUT_VERBOSE_TRACE(functionBody, _u(", value: 0x%p"), value);
             if (boxStackInstance)
             {
    +            // Do not deepCopy in this call to BoxStackInstance because this should be used for
    +            // bailing out, where a shallow copy that is cached is needed to ensure that multiple
    +            // vars pointing to the same boxed object reuse the new boxed value.
                 Js::Var oldValue = value;
    -            value = Js::JavascriptOperators::BoxStackInstance(oldValue, functionBody->GetScriptContext(), /* allowStackFunction */ true, deepCopy);
    +            value = Js::JavascriptOperators::BoxStackInstance(oldValue, functionBody->GetScriptContext(), /* allowStackFunction */ true, false /* deepCopy */);
     
     #if ENABLE_DEBUG_CONFIG_OPTIONS
                 if (oldValue != value)
    
  • lib/Backend/InlineeFrameInfo.h+3 3 modified
    @@ -108,7 +108,7 @@ struct InlineeFrameRecord
         }
     
         void PopulateParent(Func* func);
    -    void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack, bool deepCopy);
    +    void RestoreFrames(Js::FunctionBody* functionBody, InlinedFrameLayout* outerMostInlinee, Js::JavascriptCallStackLayout* callstack, bool boxValues);
         void Finalize(Func* inlinee, uint currentOffset);
     #if DBG_DUMP
         void Dump() const;
    @@ -123,8 +123,8 @@ struct InlineeFrameRecord
         }
     
     private:
    -    void Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *outerMostFrame, Js::JavascriptCallStackLayout * layout, bool deepCopy) const;
    -    Js::Var Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool deepCopy) const;
    +    void Restore(Js::FunctionBody* functionBody, InlinedFrameLayout *outerMostFrame, Js::JavascriptCallStackLayout * layout, bool boxValues) const;
    +    Js::Var Restore(int offset, bool isFloat64, bool isInt32, Js::JavascriptCallStackLayout * layout, Js::FunctionBody* functionBody, bool boxValue) const;
         InlineeFrameRecord* Reverse();
     };
     
    
  • lib/Runtime/Base/Debug.cpp+1 1 modified
    @@ -43,7 +43,7 @@ WCHAR* DumpCallStackFull(uint frameCount, bool print)
     
                 for (uint i = 0; i < callInfo.Count; i++)
                 {
    -                StringCchPrintf(buffer, _countof(buffer), _u(", 0x%p"), walker.GetJavascriptArgs()[i]);
    +                StringCchPrintf(buffer, _countof(buffer), _u(", 0x%p"), walker.GetJavascriptArgs(false /*boxArgs*/)[i]);
                     sb.AppendSz(buffer);
                 }
                 StringCchPrintf(buffer, _countof(buffer), _u(")[%s (%u, %d)]\n"), sourceFileName, line + 1, column + 1);
    
  • lib/Runtime/Language/JavascriptStackWalker.cpp+35 17 modified
    @@ -263,14 +263,14 @@ namespace Js
             this->GetCurrentArgv()[JavascriptFunctionArgIndex_ArgumentsObject] = args;
         }
     
    -    Js::Var * JavascriptStackWalker::GetJavascriptArgs() const
    +    Js::Var * JavascriptStackWalker::GetJavascriptArgs(bool boxArgsAndDeepCopy) const
         {
             Assert(this->IsJavascriptFrame());
     
     #if ENABLE_NATIVE_CODEGEN
             if (inlinedFramesBeingWalked)
             {
    -            return inlinedFrameWalker.GetArgv(/* includeThis = */ false);
    +            return inlinedFrameWalker.GetArgv(/* includeThis */ false, boxArgsAndDeepCopy);
             }
             else
     #endif
    @@ -450,7 +450,7 @@ namespace Js
                 // are inlined frames on the stack the InlineeCallInfo of the first inlined frame
                 // has the native offset of the current physical frame.
                 Assert(!*inlinee);
    -            InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo, false /*noAlloc*/, false /*deepCopy*/);
    +            InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, ScriptFunction::FromVar(parentFunction), PreviousInterpreterFrameIsFromBailout(), loopNum, this, useInternalFrameInfo, false /*noAlloc*/);
                 inlineeOffset = tmpFrameWalker.GetBottomMostInlineeOffset();
                 tmpFrameWalker.Close();
             }
    @@ -555,7 +555,7 @@ namespace Js
                             }
     
                             bool hasInlinedFramesOnStack = InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame,
    -                            ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/, false /*noAlloc*/, this->deepCopyForArgs);
    +                            ScriptFunction::FromVar(function), true /*fromBailout*/, loopNum, this, false /*useInternalFrameInfo*/, false /*noAlloc*/);
     
                             if (hasInlinedFramesOnStack)
                             {
    @@ -611,8 +611,7 @@ namespace Js
                             -1,     // loopNum
                             nullptr,// walker
                             false,  // useInternalFrameInfo
    -                        false,  // noAlloc
    -                        this->deepCopyForArgs
    +                        false   // noAlloc
                         );
                         if (inlinedFramesFound)
                         {
    @@ -658,8 +657,7 @@ namespace Js
         _NOINLINE
         JavascriptStackWalker::JavascriptStackWalker(ScriptContext * scriptContext, bool useEERContext, PVOID returnAddress, bool _forceFullWalk /*=false*/) :
             inlinedFrameCallInfo(CallFlags_None, 0), shouldDetectPartiallyInitializedInterpreterFrame(true), forceFullWalk(_forceFullWalk),
    -        previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false),
    -        deepCopyForArgs(false)
    +        previousInterpreterFrameIsFromBailout(false), previousInterpreterFrameIsForLoopBody(false), hasInlinedFramesOnStack(false)
         {
             if (scriptContext == NULL)
             {
    @@ -955,7 +953,7 @@ namespace Js
                     Assert(this->interpreterFrame->TestFlags(Js::InterpreterStackFrameFlags_FromBailOut));
                     InlinedFrameWalker tmpFrameWalker;
                     Assert(InlinedFrameWalker::FromPhysicalFrame(tmpFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
    -                    true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/, false /*deepCopy*/));
    +                    true /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, true /*noAlloc*/));
                     tmpFrameWalker.Close();
                 }
     #endif //DBG
    @@ -1002,7 +1000,7 @@ namespace Js
                 {
                     if (includeInlineFrames &&
                         InlinedFrameWalker::FromPhysicalFrame(inlinedFrameWalker, currentFrame, Js::ScriptFunction::FromVar(argv[JavascriptFunctionArgIndex_Function]),
    -                        false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, false /*noAlloc*/, this->deepCopyForArgs))
    +                        false /*fromBailout*/, this->tempInterpreterFrame->GetCurrentLoopNum(), this, false /*useInternalFrameInfo*/, false /*noAlloc*/))
                     {
                         // Found inlined frames in a jitted loop body. We dont want to skip the inlined frames; walk all of them before setting codeAddress on lastInternalFrameInfo.
                         // DeepCopy here because, if there is an inlinee in a loop body, FromPhysicalFrame won't be called from UpdateFrame
    @@ -1246,7 +1244,7 @@ namespace Js
     
     #if ENABLE_NATIVE_CODEGEN
         bool InlinedFrameWalker::FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout,
    -        int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc, bool deepCopy)
    +        int loopNum, const JavascriptStackWalker * const stackWalker, bool useInternalFrameInfo, bool noAlloc)
         {
             bool inlinedFramesFound = false;
             FunctionBody* parentFunctionBody = parent->GetFunctionBody();
    @@ -1299,7 +1297,7 @@ namespace Js
     
                     if (record)
                     {
    -                    record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer), deepCopy);
    +                    record->RestoreFrames(parent->GetFunctionBody(), outerMostFrame, JavascriptCallStackLayout::FromFramePointer(framePointer), false /* boxValues */);
                     }
                 }
     
    @@ -1366,26 +1364,46 @@ namespace Js
             return currentFrame->callInfo.Count;
         }
     
    -    Js::Var *InlinedFrameWalker::GetArgv(bool includeThis /* = true */) const
    +    // Note: the boxArgsAndDeepCopy parameter should be true when a copy of the JS args must be ensured to
    +    // be on the heap. This results in a new array of Vars with deep copied boxed values (where
    +    // appropriate).
    +    // Otherwise, this parameter should be false. For instance, if the args will only be used
    +    // internally to gather type info, the values are not boxed (so, some Vars may still be on
    +    // the stack) and the array of the current frame is returned.
    +    Js::Var *InlinedFrameWalker::GetArgv(bool includeThis, bool boxArgsAndDeepCopy) const
         {
             InlinedFrameWalker::InlinedFrame *const currentFrame = GetCurrentFrame();
             Assert(currentFrame);
     
             uint firstArg = includeThis ? InlinedFrameArgIndex_This : InlinedFrameArgIndex_SecondScriptArg;
    -        Js::Var *args = &currentFrame->argv[firstArg];
    +        size_t argCount = this->GetArgc() - firstArg;
    +        Js::Var *args;
    +        if (!boxArgsAndDeepCopy)
    +        {
    +            args = &currentFrame->argv[firstArg];
    +
    +        }
    +        else
    +        {
    +            args = RecyclerNewArray(parentFunction->GetScriptContext()->GetRecycler(), Js::Var, argCount);
    +            for (size_t i = 0; i < argCount; i++)
    +            {
    +                args[i] = currentFrame->argv[firstArg + i];
    +            }
     
    -        this->FinalizeStackValues(args, this->GetArgc() - firstArg);
    +            this->FinalizeStackValues(args, argCount, true /*deepCopy*/);
    +        }
     
             return args;
         }
     
    -    void InlinedFrameWalker::FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount) const
    +    void InlinedFrameWalker::FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount, bool deepCopy) const
         {
             ScriptContext *scriptContext = this->GetFunctionObject()->GetScriptContext();
     
             for (size_t i = 0; i < argCount; i++)
             {
    -            args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext, false /*allowStackFunction*/, false /*deepCopy*/);
    +            args[i] = Js::JavascriptOperators::BoxStackInstance(args[i], scriptContext, false /*allowStackFunction*/, deepCopy);
             }
         }
     
    
  • lib/Runtime/Language/JavascriptStackWalker.h+4 6 modified
    @@ -97,11 +97,11 @@ namespace Js
             }
     
             static bool             FromPhysicalFrame(InlinedFrameWalker& self, StackFrame& physicalFrame, Js::ScriptFunction *parent, bool fromBailout,
    -                                                  int loopNum, const JavascriptStackWalker * const walker, bool useInternalFrameInfo, bool noAlloc, bool deepCopy);
    +                                                  int loopNum, const JavascriptStackWalker * const walker, bool useInternalFrameInfo, bool noAlloc);
             void                    Close();
             bool                    Next(CallInfo& callInfo);
             size_t                  GetArgc() const;
    -        Js::Var                *GetArgv(bool includeThis = true) const;
    +        Js::Var                *GetArgv(bool includeThis, bool boxArgsAndDeepCopy) const;
             Js::JavascriptFunction *GetFunctionObject() const;
             void                    SetFunctionObject(Js::JavascriptFunction * function);
             Js::Var                 GetArgumentsObject() const;
    @@ -113,7 +113,7 @@ namespace Js
             uint32                  GetCurrentInlineeOffset() const;
             uint32                  GetBottomMostInlineeOffset() const;
             Js::JavascriptFunction *GetBottomMostFunctionObject() const;
    -        void                    FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount) const;
    +        void                    FinalizeStackValues(__in_ecount(argCount) Js::Var args[], size_t argCount, bool deepCopy) const;
             int32                   GetFrameCount() { return frameCount; }
     
         private:
    @@ -218,7 +218,7 @@ namespace Js
             CallInfo GetCallInfo(bool includeInlinedFrames = true) const;
             CallInfo GetCallInfoFromPhysicalFrame() const;
             bool GetThis(Var *pThis, int moduleId) const;
    -        Js::Var * GetJavascriptArgs() const;
    +        Js::Var * GetJavascriptArgs(bool boxArgsAndDeepCopy) const;
             void **GetCurrentArgv() const;
     
             ScriptContext* GetCurrentScriptContext() const;
    @@ -310,7 +310,6 @@ namespace Js
                 return previousInterpreterFrameIsFromBailout;
             }
     
    -        void SetDeepCopyForArguments() { deepCopyForArgs = true; }
     #if DBG
             static bool ValidateTopJitFrame(Js::ScriptContext* scriptContext);
     #endif
    @@ -335,7 +334,6 @@ namespace Js
             bool                    previousInterpreterFrameIsFromBailout : 1;
             bool                    previousInterpreterFrameIsForLoopBody : 1;
             bool                    forceFullWalk               : 1; // ignoring hasCaller
    -        bool                    deepCopyForArgs             : 1; // indicates when Var's data should be deep-copied when gathering Arguments for the frame
     
             Var GetThisFromFrame() const;                   // returns 'this' object from the physical frame
             Var GetCurrentArgumentsObject() const;          // returns arguments object from the current frame, which may be virtual (belonging to an inlinee)
    
  • lib/Runtime/Language/StackTraceArguments.cpp+3 1 modified
    @@ -73,7 +73,9 @@ namespace Js {
                 if (numberOfArguments > 0) numberOfArguments --; // Don't consider 'this'
                 for (int64 j = 0; j < numberOfArguments && j < MaxNumberOfDisplayedArgumentsInStack; j ++)
                 {
    -                types |= ObjectToTypeCode(walker.GetJavascriptArgs()[j]) << 3*j; // maximal code is 7, so we can use 3 bits to store it
    +                // Since the Args are only used to get the type, no need to box the Vars to
    +                // move them to the heap from the stack
    +                types |= ObjectToTypeCode(walker.GetJavascriptArgs(false /*boxArgsAndDeepCopy*/)[j]) << 3 * j; // maximal code is 7, so we can use 3 bits to store it
                 }
                 if (numberOfArguments > MaxNumberOfDisplayedArgumentsInStack)
                 {
    
  • lib/Runtime/Library/ArgumentsObject.cpp+1 72 modified
    @@ -26,78 +26,7 @@ namespace Js
             stringBuilder->AppendCppLiteral(_u("Object, (Arguments)"));
             return TRUE;
         }
    -
    -    Var ArgumentsObject::GetCaller(ScriptContext * scriptContext)
    -    {
    -        JavascriptStackWalker walker(scriptContext);
    -
    -        if (!this->AdvanceWalkerToArgsFrame(&walker))
    -        {
    -            return scriptContext->GetLibrary()->GetNull();
    -        }
    -
    -        return ArgumentsObject::GetCaller(scriptContext, &walker, false);
    -    }
    -
    -    Var ArgumentsObject::GetCaller(ScriptContext * scriptContext, JavascriptStackWalker *walker, bool skipGlobal)
    -    {
    -        // The arguments.caller property is equivalent to callee.caller.arguments - that is, it's the
    -        // caller's arguments object (if any). Just fetch the caller and compute its arguments.
    -        JavascriptFunction* funcCaller = nullptr;
    -
    -        while (walker->GetCaller(&funcCaller))
    -        {
    -            if (walker->IsCallerGlobalFunction())
    -            {
    -                // Caller is global/eval. If we're in IE9 mode, and the caller is eval,
    -                // keep looking. Otherwise, caller is null.
    -                if (skipGlobal || walker->IsEvalCaller())
    -                {
    -                    continue;
    -                }
    -                funcCaller = nullptr;
    -            }
    -            break;
    -        }
    -
    -        if (funcCaller == nullptr)
    -        {
    -            return scriptContext->GetLibrary()->GetNull();
    -        }
    -
    -        AssertMsg(JavascriptOperators::GetTypeId(funcCaller) == TypeIds_Function, "non function caller");
    -
    -        const CallInfo callInfo = walker->GetCallInfo();
    -        uint32 paramCount = callInfo.Count;
    -        CallFlags flags = callInfo.Flags;
    -
    -        if (paramCount == 0 || (flags & CallFlags_Eval))
    -        {
    -            // The caller is the "global function" or eval, so we return "null".
    -            return scriptContext->GetLibrary()->GetNull();
    -        }
    -
    -        if (!walker->GetCurrentFunction()->IsScriptFunction())
    -        {
    -            // builtin function do not have an argument object - return null.
    -            return scriptContext->GetLibrary()->GetNull();
    -        }
    -
    -        // Create new arguments object, everytime this is requested for, with the actuals value.
    -        Var args = nullptr;
    -
    -        args = JavascriptOperators::LoadHeapArguments(
    -            funcCaller,
    -            paramCount - 1,
    -            walker->GetJavascriptArgs(),
    -            scriptContext->GetLibrary()->GetNull(),
    -            scriptContext->GetLibrary()->GetNull(),
    -            scriptContext,
    -            /* formalsAreLetDecls */ false);
    -
    -        return args;
    -    }
    -
    +    
         bool ArgumentsObject::Is(Var aValue)
         {
             return JavascriptOperators::GetTypeId(aValue) == TypeIds_Arguments;
    
  • lib/Runtime/Library/ArgumentsObject.h+0 2 modified
    @@ -18,8 +18,6 @@ namespace Js
             {
                 Assert(type->GetTypeId() == TypeIds_Arguments);
             }
    -        Var GetCaller(ScriptContext * scriptContext);
    -        static Var GetCaller(ScriptContext * scriptContext, JavascriptStackWalker *walker, bool skipGlobal);
     
             static bool Is(Var aValue);
     
    
  • lib/Runtime/Library/JavascriptArray.cpp+21 6 modified
    @@ -11679,12 +11679,24 @@ namespace Js
         T * JavascriptArray::BoxStackInstance(T * instance, bool deepCopy)
         {
             Assert(ThreadContext::IsOnStack(instance));
    -        // On the stack, the we reserved a pointer before the object as to store the boxed value
    -        T ** boxedInstanceRef = ((T **)instance) - 1;
    -        T * boxedInstance = *boxedInstanceRef;
    -        if (boxedInstance)
    +        T * boxedInstance;
    +        T ** boxedInstanceRef;
    +        if (!deepCopy)
    +        {
    +            // On the stack, the we reserved a pointer before the object as to store the boxed value
    +            boxedInstanceRef = ((T **)instance) - 1;
    +            boxedInstance = *boxedInstanceRef;
    +            if (boxedInstance)
    +            {
    +                return boxedInstance;
    +            }
    +        }
    +        else
             {
    -            return boxedInstance;
    +            // When doing a deep copy, do not cache the boxed value to ensure that only shallow copies
    +            // are reused
    +            boxedInstance = nullptr;
    +            boxedInstanceRef = nullptr;
             }
     
             const size_t inlineSlotsSize = instance->GetTypeHandler()->GetInlineSlotsSize();
    @@ -11703,7 +11715,10 @@ namespace Js
                 boxedInstance = RecyclerNew(instance->GetRecycler(), T, instance, false, false);
             }
     
    -        *boxedInstanceRef = boxedInstance;
    +        if (boxedInstanceRef != nullptr)
    +        {
    +            *boxedInstanceRef = boxedInstance;
    +        }
             return boxedInstance;
         }
     
    
  • lib/Runtime/Library/JavascriptFunction.cpp+3 3 modified
    @@ -2871,7 +2871,6 @@ void __cdecl _alloca_probe_16()
             // and foo.arguments[n] will be maintained after this object is returned.
     
             JavascriptStackWalker walker(scriptContext);
    -        walker.SetDeepCopyForArguments();
     
             if (walker.WalkToTarget(this))
             {
    @@ -2882,12 +2881,13 @@ void __cdecl _alloca_probe_16()
                 else
                 {
                     Var args = nullptr;
    -                //Create a copy of the arguments and return it.
    +                // Since the arguments will be returned back to script, box the arguments to ensure a copy of
    +                // them with their own lifetime (as well as move any from the stack to the heap).
     
                     const CallInfo callInfo = walker.GetCallInfo();
                     args = JavascriptOperators::LoadHeapArguments(
                         this, callInfo.Count - 1,
    -                    walker.GetJavascriptArgs(),
    +                    walker.GetJavascriptArgs(true /* boxArgsAndDeepCopy */),
                         scriptContext->GetLibrary()->GetNull(),
                         scriptContext->GetLibrary()->GetNull(),
                         scriptContext,
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

12

News mentions

0

No linked articles in our index yet.