VYPR
High severity7.5NVD Advisory· Published Sep 14, 2016· Updated May 6, 2026

CVE-2016-3350

CVE-2016-3350

Description

The Chakra JavaScript engine in Microsoft Edge allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted web site, aka "Scripting Engine Memory Corruption Vulnerability," a different vulnerability than CVE-2016-3377.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
Microsoft.ChakraCoreNuGet
< 1.2.11.2.1

Affected products

1

Patches

1
24c4d7df8199

This change contains combined fixes for CVE-2016-3350, CVE-2016-3377 and a defense in depth change in the CustomHeap

https://github.com/chakra-core/ChakraCoreHitesh KanwathirthaSep 15, 2016via ghsa
10 files changed · +443 49
  • lib/Common/DataStructures/UnitBitVector.h+5 0 modified
    @@ -287,6 +287,11 @@ class BVUnitT
             T mask = ((T)AllOnesMask) >> (BitsPerWord - length) << index;
             return (this->word & mask) == mask;
         }
    +    BOOLEAN TestAnyInRange(const BVIndex index, uint length) const
    +    {
    +        T mask = ((T)AllOnesMask) >> (BitsPerWord - length) << index;
    +        return (this->word & mask) != 0;
    +    }
         void SetRange(const BVIndex index, uint length)
         {
             T mask = ((T)AllOnesMask) >> (BitsPerWord - length) << index;
    
  • lib/Common/Memory/CustomHeap.cpp+53 32 modified
    @@ -485,7 +485,7 @@ void Heap::FreeLargeObjects()
     #endif
             this->codePageAllocators->Release(allocation.address, allocation.GetPageCount(), allocation.largeObjectAllocation.segment);
     
    -            largeObjectIter.RemoveCurrent(this->auxiliaryAllocator);
    +        largeObjectIter.RemoveCurrent(this->auxiliaryAllocator);
         }
         NEXT_DLISTBASE_ENTRY_EDITING;
     }
    @@ -519,7 +519,13 @@ bool Heap::AllocInPage(Page* page, size_t bytes, ushort pdataCount, ushort xdata
     
         uint length = GetChunkSizeForBytes(bytes);
         BVIndex index = GetFreeIndexForPage(page, bytes);
    -    Assert(index != BVInvalidIndex);
    +    
    +    if (index == BVInvalidIndex)
    +    {
    +        CustomHeap_BadPageState_fatal_error((ULONG_PTR)this);
    +        return false;
    +    }
    +
         char* address = page->address + Page::Alignment * index;
     
     #if PDATA_ENABLED
    @@ -562,6 +568,13 @@ bool Heap::AllocInPage(Page* page, size_t bytes, ushort pdataCount, ushort xdata
         this->freeObjectSize -= bytes;
     #endif
     
    +    //Section of the Page should already be freed.
    +    if (!page->freeBitVector.TestRange(index, length))
    +    {
    +        CustomHeap_BadPageState_fatal_error((ULONG_PTR)this);
    +        return false;
    +    }
    +
         page->freeBitVector.ClearRange(index, length);
         VerboseHeapTrace(_u("ChunkSize: %d, Index: %d, Free bit vector in page: "), length, index);
     
    @@ -729,18 +742,19 @@ bool Heap::FreeAllocation(Allocation* object)
         unsigned int length = GetChunkSizeForBytes(object->size);
         BVIndex index = GetIndexInPage(page, object->address);
     
    -#if DBG
    -    // Make sure that it's not already been freed
    -    for (BVIndex i = index; i < length; i++)
    +    uint freeBitsCount = page->freeBitVector.Count();
    +
    +    // Make sure that the section under interest or the whole page has not already been freed
    +    if (page->IsEmpty() || page->freeBitVector.TestAnyInRange(index, length))
         {
    -        Assert(!page->freeBitVector.Test(i));
    +        CustomHeap_BadPageState_fatal_error((ULONG_PTR)this);
    +        return false;
         }
    -#endif
     
         if (page->inFullList)
         {
             VerboseHeapTrace(_u("Recycling page 0x%p because address 0x%p of size %d was freed\n"), page->address, object->address, object->size);
    -
    +       
             // If the object being freed is equal to the page size, we're
             // going to remove it anyway so don't add it to a bucket
             if (object->size != pageSize)
    @@ -777,14 +791,43 @@ bool Heap::FreeAllocation(Allocation* object)
         // If the page is about to become empty then we should not need
         // to set it to executable and we don't expect to restore the
         // previous protection settings.
    -    if (page->freeBitVector.Count() == BVUnit::BitsPerWord - length)
    +    if (freeBitsCount == BVUnit::BitsPerWord - length)
         {
             EnsureAllocationWriteable(object);
    +        FreeAllocationHelper(object, index, length);
    +        Assert(page->IsEmpty());
    +
    +        this->buckets[page->currentBucket].RemoveElement(this->auxiliaryAllocator, page);
    +        return false;
         }
         else
         {
             EnsureAllocationExecuteWriteable(object);
    +
    +        FreeAllocationHelper(object, index, length);
    +
    +        // after freeing part of the page, the page should be in PAGE_EXECUTE_READWRITE protection, and turning to PAGE_EXECUTE (always with TARGETS_NO_UPDATE state)
    +
    +        DWORD protectFlags = 0;
    +
    +        if (AutoSystemInfo::Data.IsCFGEnabled())
    +        {
    +            protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
    +        }
    +        else
    +        {
    +            protectFlags = PAGE_EXECUTE;
    +        }
    +
    +        this->codePageAllocators->ProtectPages(page->address, 1, segment, protectFlags, PAGE_EXECUTE_READWRITE);
    +        
    +        return true;
         }
    +}
    +
    +void Heap::FreeAllocationHelper(Allocation* object, BVIndex index, uint length)
    +{
    +    Page* page = object->page;
     
         // Fill the old buffer with debug breaks
         CustomHeap::FillDebugBreak((BYTE *)object->address, object->size);
    @@ -796,6 +839,7 @@ bool Heap::FreeAllocation(Allocation* object)
         VerboseHeapTrace(_u("\n"));
     
         page->freeBitVector.SetRange(index, length);
    +
         VerboseHeapTrace(_u("Free bit vector in page: "), length, index);
     #if VERBOSE_HEAP
         page->freeBitVector.DumpWord();
    @@ -808,29 +852,6 @@ bool Heap::FreeAllocation(Allocation* object)
     #endif
     
         this->auxiliaryAllocator->Free(object, sizeof(Allocation));
    -
    -    if (page->IsEmpty())
    -    {
    -        this->buckets[page->currentBucket].RemoveElement(this->auxiliaryAllocator, page);
    -        return false;
    -    }
    -    else // after freeing part of the page, the page should be in PAGE_EXECUTE_READWRITE protection, and turning to PAGE_EXECUTE (always with TARGETS_NO_UPDATE state)
    -    {
    -        DWORD protectFlags = 0;
    -
    -        if (AutoSystemInfo::Data.IsCFGEnabled())
    -        {
    -            protectFlags = PAGE_EXECUTE_RO_TARGETS_NO_UPDATE;
    -        }
    -        else
    -        {
    -            protectFlags = PAGE_EXECUTE;
    -        }
    -
    -        this->codePageAllocators->ProtectPages(page->address, 1, segment, protectFlags, PAGE_EXECUTE_READWRITE);
    -        
    -        return true;
    -    }
     }
     
     void Heap::FreeDecommittedBuckets()
    
  • lib/Common/Memory/CustomHeap.h+1 0 modified
    @@ -504,6 +504,7 @@ class Heap
         void FreeBucket(DListBase<Page>* bucket, bool freeOnlyEmptyPages);
         void FreePage(Page* page);
         bool FreeAllocation(Allocation* allocation);
    +    void FreeAllocationHelper(Allocation * allocation, BVIndex index, uint length);
     
     #if PDATA_ENABLED
         void FreeXdata(XDataAllocation* xdata, void* segment);
    
  • lib/Common/Memory/PageAllocator.h+2 2 modified
    @@ -518,8 +518,8 @@ class PageAllocatorBase
     #if DBG_DUMP
         virtual void DumpStats() const;
     #endif
    -    virtual PageSegmentBase<TVirtualAlloc> * AddPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList);
    -    static PageSegmentBase<TVirtualAlloc> * AllocPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList, 
    +    PageSegmentBase<TVirtualAlloc> * AddPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList);
    +    static PageSegmentBase<TVirtualAlloc> * AllocPageSegment(DListBase<PageSegmentBase<TVirtualAlloc>>& segmentList,
         PageAllocatorBase<TVirtualAlloc> * pageAllocator, bool committed, bool allocated);
     
         // Zero Pages
    
  • lib/Parser/Parse.cpp+19 9 modified
    @@ -816,6 +816,7 @@ Symbol* Parser::AddDeclForPid(ParseNodePtr pnode, IdentPtr pid, SymbolType symbo
             && blockInfo->pnodeBlock->sxBlock.blockType == PnodeBlockType::Function
             && blockInfo->pBlockInfoOuter != nullptr
             && blockInfo->pBlockInfoOuter->pnodeBlock->sxBlock.blockType == PnodeBlockType::Parameter
    +        && blockInfo->pnodeBlock->sxBlock.scope->GetScopeType() != ScopeType_FuncExpr
             && blockInfo->pBlockInfoOuter->pnodeBlock->sxBlock.scope->GetCanMergeWithBodyScope())
         {
             blockInfo = blockInfo->pBlockInfoOuter;
    @@ -5029,6 +5030,13 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncPare
                             }
                             return false;
                         });
    +
    +                    if (wellKnownPropertyPids.arguments->GetTopRef() && wellKnownPropertyPids.arguments->GetTopRef()->GetScopeId() > pnodeFnc->sxFnc.pnodeScopes->sxBlock.blockId)
    +                    {
    +                        Assert(pnodeFnc->sxFnc.UsesArguments());
    +                        // Arguments symbol is captured in the param scope
    +                        paramScope->SetCannotMergeWithBodyScope();
    +                    }
                     }
                 }
             }
    @@ -5895,13 +5903,6 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u
                 pnodeFnc->sxFnc.pid = m_phtbl->PidHashNameLen(
                     m_pscan->PchBase() + ichMinNames, ichLimNames - ichMinNames);
             }
    -
    -        if(pnodeFnc->sxFnc.pid == wellKnownPropertyPids.arguments && fDeclaration && pnodeFncParent)
    -        {
    -            // This function declaration (or function expression in compat modes) overrides the built-in arguments object of the
    -            // parent function
    -            pnodeFncParent->grfpn |= PNodeFlags::fpnArguments_overriddenByDecl;
    -        }
         }
     
         return true;
    @@ -6670,10 +6671,11 @@ void Parser::AddArgumentsNodeToVars(ParseNodePtr pnodeFnc)
         }
         else
         {
    +        ParseNodePtr argNode = nullptr;
             if(m_ppnodeVar == &pnodeFnc->sxFnc.pnodeVars)
             {
                 // There were no var declarations in the function
    -            CreateVarDeclNode(wellKnownPropertyPids.arguments, STVariable, true, pnodeFnc)->grfpn |= PNodeFlags::fpnArguments;
    +            argNode = CreateVarDeclNode(wellKnownPropertyPids.arguments, STVariable, true, pnodeFnc);
             }
             else
             {
    @@ -6684,10 +6686,18 @@ void Parser::AddArgumentsNodeToVars(ParseNodePtr pnodeFnc)
                 // object until it is replaced with something else.
                 ParseNodePtr *const ppnodeVarSave = m_ppnodeVar;
                 m_ppnodeVar = &pnodeFnc->sxFnc.pnodeVars;
    -            CreateVarDeclNode(wellKnownPropertyPids.arguments, STVariable, true, pnodeFnc)->grfpn |= PNodeFlags::fpnArguments;
    +            argNode = CreateVarDeclNode(wellKnownPropertyPids.arguments, STVariable, true, pnodeFnc);
                 m_ppnodeVar = ppnodeVarSave;
             }
     
    +        Assert(argNode);
    +        argNode->grfpn |= PNodeFlags::fpnArguments;
    +
    +        // When a function definition with the name arguments occurs in the body the declaration of the arguments symbol will
    +        // be set to that function declaration. We should change it to arguments declaration from the param scope as it may be
    +        // used in the param scope and we have to load the arguments.
    +        argNode->sxVar.sym->SetDecl(argNode);
    +
             pnodeFnc->sxFnc.SetHasReferenceableBuiltInArguments(true);
         }
     }
    
  • lib/Runtime/ByteCode/ByteCodeEmitter.cpp+3 1 modified
    @@ -3693,7 +3693,9 @@ void EnsureFncDeclScopeSlot(ParseNode *pnodeFnc, FuncInfo *funcInfo)
         {
             Assert(pnodeFnc->sxFnc.pnodeName->nop == knopVarDecl);
             Symbol *sym = pnodeFnc->sxFnc.pnodeName->sxVar.sym;
    -        if (sym)
    +        // If this function is shadowing the arguments symbol in body then skip it.
    +        // We will allocate scope slot for the arguments symbol during EmitLocalPropInit.
    +        if (sym && !sym->GetIsArguments())
             {
                 sym->EnsureScopeSlot(funcInfo);
             }
    
  • lib/Runtime/Library/JavascriptArray.cpp+1 1 modified
    @@ -9019,7 +9019,7 @@ namespace Js
     
                         if (newArr)
                         {
    -                        newArr->DirectSetItemAt(k, mappedValue);
    +                        newArr->SetItem(k, mappedValue, PropertyOperation_None);
                         }
                         else
                         {
    
  • test/es6/default.js+235 1 modified
    @@ -380,7 +380,241 @@ var tests = [
         body: function () {
    
             assert.doesNotThrow(function () { eval("[ (a = function () { }) => {} ];"); }, "Lambda defined, inside an array literal, has a default as a function should not assert");
    
         }
    
    -  }
    
    +  },
    
    +  {
    
    +    name: "Shadowing arguments symbol",
    
    +    body: function () {
    
    +        function f1(a, b = arguments[0]) {
    
    +            assert.areEqual(1, arguments[0], "Initial value of arguments symbol in the body should be same as the arguments from the param scope");
    
    +            var arguments = [10, 20];
    
    +            assert.areEqual(1, b, "Arguments value is the initial value in the param scope too");
    
    +            assert.areEqual(10, arguments[0], "Arguments value is updated in the body");
    
    +        }
    
    +        f1(1);
    
    +
    
    +        function f2(a = 1, arguments) {
    
    +            assert.areEqual(2, arguments, "Initial value of arguments symbol in the body should be same as the arguments from the param scope");
    
    +            var arguments = [10, 20];
    
    +            assert.areEqual(10, arguments[0], "Arguments value is updated in the body");
    
    +        }
    
    +        f2(undefined, 2);
    
    +
    
    +        function f3(a, b = arguments[0]) {
    
    +            assert.areEqual(10, arguments(), "Arguments symbol is overwritten by the the function definition");
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +            assert.areEqual(1, b, "Arguments value is the initial value in the param scope too");
    
    +        }
    
    +        f3(1);
    
    +
    
    +        function f4(a = 1, arguments, c = arguments) {
    
    +            assert.areEqual(10, arguments(), "In the body function definition shadows the formal");
    
    +            assert.areEqual(2, c, "Value of the formal is assigned properly");
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +        }
    
    +        f4(undefined, 2);
    
    +
    
    +        function f5(a, b = arguments) {
    
    +            function arguments(c) {
    
    +                return arguments;
    
    +            }
    
    +            assert.areEqual(30, arguments(10, 20, 30)[2], "Inside the arguments function the arguments symbol should points to the passed in values");
    
    +            assert.areEqual(4, b[3], "In the param scope arguments symbol referes to the passed in values");
    
    +        }
    
    +        f5(1, undefined, 3, 4, 5);
    
    +
    
    +        function f6(a, b = arguments) {
    
    +            function arguments(c) {
    
    +                if (!arguments.length) {
    
    +                    return arguments.callee(10, 20, 30);
    
    +                }
    
    +                return arguments;
    
    +            }
    
    +            assert.areEqual(20, arguments()[1], "In the function body arguments refers to the inner function");
    
    +            assert.areEqual(3, b[2], "In the param scope arguments symbol referes to the passed in values");
    
    +        }
    
    +        f6(1, undefined, 3, 4);
    
    +
    
    +        function f7(a, b = function arguments(c) {
    
    +            if (!c) {
    
    +                return arguments.callee(10, 20);
    
    +            }
    
    +            return c + arguments[1];
    
    +        }) {
    
    +            assert.areEqual(30, b(), "Function defined in the param scope can be called recursively");
    
    +            assert.areEqual(1, arguments[0], "Arguments symbol is unaffected by the function expression");
    
    +        }
    
    +        f7(1);
    
    +
    
    +        function f8(a, b = arguments) {
    
    +            var c = function arguments(c) {
    
    +                if (!arguments.length) {
    
    +                    return arguments.callee(10, 20, 30);
    
    +                }
    
    +                return arguments;
    
    +            }
    
    +            assert.areEqual(30, c()[2], "In the function body the arguments function expression with name is not visible");
    
    +            assert.areEqual(1, b[0], "In the param scope arguments symbol referes to the passed in values");
    
    +        }
    
    +        f8(1);
    
    +
    
    +        assert.throws(function () { eval("function f(a, b = arguments) { class arguments { } }"); }, SyntaxError, "Class cannot be named arguments", "Invalid usage of 'arguments' in strict mode");
    
    +        assert.throws(function () { eval("function f(a, arguments) { class arguments { } }"); }, SyntaxError, "Class cannot be named arguments even when one of the formal is named arguments", "Let/Const redeclaration");
    
    +
    
    +        function f9( a = 0, b = {
    
    +            arguments() {
    
    +                return 10;
    
    +            }
    
    +        }, c = arguments) {
    
    +            with (b) {
    
    +                assert.areEqual(10, arguments(), "Inside with the right the arguments function inside the object is used in the body also");
    
    +            }
    
    +            assert.areEqual(1, arguments[0], "Arguments symbol should be unaffected after with construct");
    
    +            assert.areEqual(1, c[0], "Arguments symbol from param scope should be unaffected after with construct");
    
    +        }
    
    +        f9(1);
    
    +
    
    +        function f10(a = 1, b = () => {
    
    +            assert.areEqual(undefined, arguments, "Due to the decalration in the body arguments symbol is shadowed inside the lambda");
    
    +            var arguments = 100;
    
    +            assert.areEqual(100, arguments, "After the assignment value of arguments is updated inside the lambda");
    
    +        }, c = arguments) {
    
    +            assert.areEqual(10, arguments[0], "In the body the value of arguments is retained");
    
    +            assert.areEqual(10, c[0], "Arguments symbol is not affected in the param scope");
    
    +            b();
    
    +        }
    
    +        f10(10);
    
    +
    
    +        function f11(a = 1, b = () => {
    
    +            assert.areEqual(100, arguments(), "Inside the lambda the function definition shadows the parent's arguments symbol");
    
    +            function arguments() {
    
    +                return 100;
    
    +            }
    
    +        }, c = arguments) {
    
    +            assert.areEqual(10, arguments[0], "In the body the value of arguments is retained");
    
    +            b();
    
    +            assert.areEqual(10, c[0], "Arguments symbol is not affected in the param scope");
    
    +        }
    
    +        f11(10);
    
    +
    
    +        function f12({a = 1, arguments}) {
    
    +            assert.areEqual(2, arguments, "Initial value of arguments symbol in the body should be same as the arguments from the param scope's destructured pattern");
    
    +            var arguments = [10, 20];
    
    +            assert.areEqual(10, arguments[0], "Arguments value is updated in the body");
    
    +        }
    
    +        f12({arguments : 2});
    
    +
    
    +        function f13(a = 1, {arguments, c = arguments}) {
    
    +            assert.areEqual(10, arguments(), "In the body function definition shadows the destructured formal");
    
    +            assert.areEqual(2, c, "Value of the formal is assigned properly");
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +        }
    
    +        f13(undefined, { arguments: 2 });
    
    +
    
    +        function f14(a, b = arguments[0]) {
    
    +            assert.areEqual(1, arguments[0], "Function in block causes a var declaration to be hoisted and the initial value should be same as the arguments symbol");
    
    +            {
    
    +                {
    
    +                    function arguments() {
    
    +                        return 10;
    
    +                    }
    
    +                }
    
    +            }
    
    +            assert.areEqual(1, b, "Arguments value is the initial value in the param scope too");
    
    +            assert.areEqual(10, arguments(), "Hoisted var binding is updated after the block is exected");
    
    +        }
    
    +        f14(1);
    
    +
    
    +        function f15() {
    
    +            function f16() {
    
    +                eval("");
    
    +                this.arguments = 1;
    
    +            }
    
    +
    
    +            var obj = new f16();
    
    +            
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +            assert.areEqual(1, obj.arguments, "Child function having eval should work fine with a duplicate arguments definition in the parent body");
    
    +        };
    
    +        f15();
    
    +    }
    
    +  },
    
    +  {
    
    +    name: "Shadowing arguments symbol - Eval",
    
    +    body: function () {
    
    +        function f1(a, b = arguments[0]) {
    
    +            assert.areEqual(1, arguments[0], "Initial value of arguments symbol in the body should be same as the arguments from the param scope");
    
    +            var arguments = [10, 20];
    
    +            assert.areEqual(1, b, "Arguments value is the initial value in the param scope too");
    
    +            assert.areEqual(10, eval("arguments[0]"), "Arguments value is updated in the body");
    
    +        }
    
    +        f1(1);
    
    +
    
    +        function f2(a = 1, arguments) {
    
    +            assert.areEqual(2, eval("arguments"), "Initial value of arguments symbol in the body should be same as the arguments from the param scope");
    
    +            var arguments = [10, 20];
    
    +            assert.areEqual(10, arguments[0], "Arguments value is updated in the body");
    
    +        }
    
    +        f2(undefined, 2);
    
    +
    
    +        function f3(a, b = arguments[0]) {
    
    +            assert.areEqual(10, eval("arguments()"), "Arguments symbol is overwritten by the the function definition");
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +            assert.areEqual(1, b, "Arguments value is the initial value in the param scope too");
    
    +        }
    
    +        f3(1);
    
    +
    
    +        function f4(a = 1, arguments, c = arguments) {
    
    +            assert.areEqual(10, arguments(), "In the body function definition shadows the formal");
    
    +            assert.areEqual(2, eval("c"), "Value of the formal is assigned properly");
    
    +            function arguments() {
    
    +                return 10;
    
    +            }
    
    +        }
    
    +        f4(undefined, 2);
    
    +
    
    +        function f5(a, b, c = arguments) {
    
    +            function arguments(c) {
    
    +                return eval("arguments");
    
    +            }
    
    +            assert.areEqual(30, arguments(10, 20, 30)[2], "In the function body arguments refers to the inner function");
    
    +            assert.areEqual(2, c[1], "In the param scope arguments symbol referes to the passed in values");
    
    +        }
    
    +        f5(1, 2, undefined, 4);
    
    +
    
    +        function f6(a, b = function arguments(c) {
    
    +            if (!c) {
    
    +                return arguments.callee(10, 20);
    
    +            }
    
    +            return c + arguments[1];
    
    +        }) {
    
    +            assert.areEqual(30, eval("b()"), "Function defined in the param scope can be called recursively");
    
    +            assert.areEqual(1, arguments[0], "Arguments symbol is unaffected by the function expression");
    
    +        }
    
    +        f6(1);
    
    +
    
    +        function f7(a, b = arguments) {
    
    +            var c = function arguments(c) {
    
    +                if (!arguments.length) {
    
    +                    return arguments.callee(10, 20, 30);
    
    +                }
    
    +                return arguments;
    
    +            }
    
    +            assert.areEqual(10, eval("c()[0]"), "In the function body the arguments function expression with name is not visible");
    
    +            assert.areEqual(4, b[3], "In the param scope arguments symbol referes to the passed in values");
    
    +        }
    
    +        f7(1, undefined, 3, 4);
    
    +    }
    
    + }
    
     ];
    
     
    
     testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
    
    
  • test/es6/default-splitscope.js+89 3 modified
    @@ -734,9 +734,18 @@ var tests = [
             assert.throws(function () { eval("function f(a = 10, b = (c = arguments) => a) { }"); }, SyntaxError, "Use of arguments symbol is not allowed in non-simple parameter list when captured in a lambda in split scope", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
             assert.throws(function () { eval("function f(a, b = () => a, c = () => { return arguments; }) { }"); }, SyntaxError, "Use of arguments symbol is not allowed in non-simple parameter list in split scope when captured by a lambda method", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
             assert.throws(function () { eval("function f(a = 10, b = () => a, c = () => () => arguments) { }"); }, SyntaxError, "Use of arguments symbol is not allowed in non-simple parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    -        assert.throws(function () { eval("function f3(a, arguments = function () { return a; } ) { }"); }, SyntaxError, "Use of arguments as a parameter name is not allowed in non-simple parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    -        assert.throws(function () { eval("function f3({a, arguments = function () { return a; }}) { }"); }, SyntaxError, "Use of arguments as a parameter name is not allowed in destructuring parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    -        assert.throws(function () { eval("function f3({a = arguments}, b = function () { return a; } ) { }"); }, SyntaxError, "Use of arguments is not allowed in destructuring parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a, arguments = function () { return a; } ) { }"); }, SyntaxError, "Use of arguments as a parameter name is not allowed in non-simple parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f({a, arguments = function () { return a; }}) { }"); }, SyntaxError, "Use of arguments as a parameter name is not allowed in destructuring parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f({a = arguments}, b = function () { return a; } ) { }"); }, SyntaxError, "Use of arguments is not allowed in destructuring parameter list in split scope when captured by nested lambda", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = () => arguments) { }"); }, SyntaxError, "Arguments cannot be captured in the param scope", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = () => arguments[0]) { }"); }, SyntaxError, "Arguments cannot be captured in the param scope", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = 1, b = () => arguments[0]) { }"); }, SyntaxError, "Arguments cannot be captured in the param scope at any position", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = () => arguments[0] + b, b = 10) { }"); }, SyntaxError, "Arguments cannot be captured in the param scope at any position", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = () => arguments) { var arguments }"); }, SyntaxError, "Arguments cannot be captured in the param scope even when duplicate definition occurs in the body", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a = () => arguments) { function arguments() { } }"); }, SyntaxError, "Arguments cannot be captured in the param scope even when duplicate definition occurs in the body", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(arguments, b = () => arguments) { }"); }, SyntaxError, "Arguments cannot be captured in the param scope even if it is a formal shadowing the actual arguments", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f({a, arguments}, b = () => a) { }"); }, SyntaxError, "Arguments cannot be used as a formal name when one of the formal is captured", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
    +        assert.throws(function () { eval("function f(a, {arguments, b = () => arguments}) { }"); }, SyntaxError, "Arguments cannot be used as a formal name when one of the formal is captured", "Use of 'arguments' in non-simple parameter list is not supported when one of the formals is captured");
             
             function f1(a, b = () => a) {
                 eval("");
    @@ -913,6 +922,83 @@ var tests = [
                 }
             }
             assert.areEqual([2, 3], f16(1, undefined, 2, 3), "Rest should remain unaffected when arguments is updated");
    +
    +        function f18(a, b = function arguments(c) {
    +            if (!c) {
    +                return arguments.callee(a, 10, 20);
    +            }
    +            return arguments;
    +        }) {
    +            assert.areEqual(10, b()[1], "Function defined in the param scope can be called recursively");
    +            assert.areEqual(1, arguments[0], "Arguments symbol is unaffected by the function expression");
    +        }
    +        f18(1);
    +
    +        function f19(a, b = arguments) {
    +            var c = function arguments(c) {
    +                if (!arguments.length) {
    +                    return arguments.callee(a, 10, 20, 30);
    +                }
    +                return arguments;
    +            }
    +            assert.areEqual(30, c()[3], "In the function body the arguments function expression with name is not visible");
    +            assert.areEqual(1, b[0], "In the param scope arguments symbol referes to the passed in values");
    +        }
    +        f19(1, undefined, 2, 3, 4);
    +
    +        function f20(a, b = function arguments(c) {
    +            if (!c) {
    +                return arguments.callee(a, 10, 20);
    +            }
    +            return eval("arguments");
    +        }) {
    +            assert.areEqual(1, b()[0], "Function defined in the param scope can be called recursively when eval occurs in its body");
    +            assert.areEqual(1, arguments[0], "Arguments symbol is unaffected by the function expression");
    +        }
    +        f20(1);
    +
    +        function f21(a, b = arguments) {
    +            var c = function arguments(c) {
    +                if (!arguments.length) {
    +                    return arguments.callee(a, 10, 20, 30);
    +                }
    +                return arguments;
    +            }
    +            assert.areEqual(30, c()[3], "In the function body the arguments function expression with name is not visible when eval is there in the body");
    +            assert.areEqual(3, eval("b[3]"), "In the param scope arguments symbol referes to the passed in values");
    +        }
    +        f21(1, undefined, 2, 3, 4);
    +
    +        function f22(a, b = () => a) {
    +            assert.areEqual(1, arguments[0], "Function in block causes a var declaration to be hoisted and the initial value should be same as the arguments symbol");
    +            {
    +                {
    +                    function arguments() {
    +                        return 10;
    +                    }
    +                }
    +            }
    +            assert.areEqual(1, b(), "Function defined in the param scope should be able to capture the formal even when arguments in overwritten the body");
    +            assert.areEqual(10, arguments(), "Hoisted var binding is updated after the block is exected");
    +        }
    +        f22(1);
    +
    +        function f23(a, b = () => a) {
    +            function f16() {
    +                eval("");
    +                this.arguments = 1;
    +            }
    +
    +            a = 10;
    +            var obj = new f16();
    +            
    +            function arguments() {
    +                return 10;
    +            }
    +            assert.areEqual(1, obj.arguments, "Inner function with eval should add the property named arguments when duplicate arguments definition occurs in the parent body");
    +            assert.areEqual(1, b(), "Formal captured from the param scope should be constrained to the param scope");
    +        };
    +        f23(1);
         }  
       },
       {
    
  • test/es6/ES6Species-bugs.js+35 0 modified
    @@ -27,6 +27,41 @@ var tests = [
                 assert.throws(function() { Array.prototype.splice.call(arr, 0, 3); }, TypeError, "TypeError when constructor[Symbol.species] is not constructor", "Function 'constructor[Symbol.species]' is not a constructor");
    
             }
    
         },
    
    +    {
    
    +        name: "Type confusion in Array.prototype.map()",
    
    +        body: function () {
    
    +            function test(){
    
    +                CollectGarbage();
    
    +
    
    +                var n = [];
    
    +                for (var i = 0; i < 0x10; i++)
    
    +                    n.push([0x12345678, 0x12345678, 0x12345678, 0x12345678]);
    
    +
    
    +                class fake extends Object {
    
    +                    static get [Symbol.species]() { return function() { return n[5]; }; };
    
    +                }
    
    +
    
    +                var f = function(a){ return a; }
    
    +
    
    +                var x = ["fluorescence", 0, 0, 0x41414141];
    
    +                var y = new Proxy(x, {
    
    +                    get: function(t, p, r) {
    
    +                        return (p == "constructor") ? fake : x[p];
    
    +                    }
    
    +                });
    
    +
    
    +                // oob write
    
    +                Array.prototype.map.apply(y, [f]);
    
    +
    
    +                for (var i = 0; i < 0x10; i++)
    
    +                    n[i][0] = 0x42424242;
    
    +
    
    +            }
    
    +
    
    +            test();
    
    +
    
    +        }
    
    +    },
    
     ];
    
     
    
     testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
    
    

Vulnerability mechanics

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

References

8

News mentions

0

No linked articles in our index yet.