Skip to content

Commit 0103740

Browse files
committed
[MERGE #4957 @sigatrev] OS#16050168: fix jit crash for splitscope using 'with' statements
Merge pull request #4957 from sigatrev:withBodyScope When 'with' statements are used in inside param scopes when param and body scopes are split, there will not always be a local closure generated. See attached test for an example case. The IRBuilder would attempt to build a RegOpnd for the closure, and would assert on a nullptr sym. The backward pass would later AV on that nullptr sym. This commit instead assigns nullptr to the param closure when there is no local closure, which is the behavior of InterpreterStackFrame::OP_BeginBodyScope()
2 parents 33ce21c + 57b03d3 commit 0103740

File tree

3 files changed

+43
-2
lines changed

3 files changed

+43
-2
lines changed

lib/Backend/IRBuilder.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6937,23 +6937,35 @@ IRBuilder::BuildEmpty(Js::OpCode newOpcode, uint32 offset)
69376937
break;
69386938

69396939
case Js::OpCode::BeginBodyScope:
6940+
{
69406941
// This marks the end of a param socpe which is not merged with body scope.
69416942
// So we have to first cache the closure so that we can use it to copy the initial values for
69426943
// body syms from corresponding param syms (LdParamSlot). Body should get its own scope slot.
69436944
Assert(!this->IsParamScopeDone());
69446945
this->SetParamScopeDone();
69456946

6947+
IR::Opnd * localClosureOpnd;
6948+
if (this->m_func->GetLocalClosureSym() != nullptr)
6949+
{
6950+
localClosureOpnd = IR::RegOpnd::New(this->m_func->GetLocalClosureSym(), TyVar, this->m_func);
6951+
}
6952+
else
6953+
{
6954+
AssertOrFailFast(this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() == 0 && !this->m_func->GetJITFunctionBody()->HasScopeObject());
6955+
localClosureOpnd = IR::IntConstOpnd::New(0, TyVar, this->m_func);
6956+
}
6957+
69466958
this->AddInstr(
69476959
IR::Instr::New(
69486960
Js::OpCode::Ld_A,
69496961
this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetParamClosureReg()),
6950-
IR::RegOpnd::New(this->m_func->GetLocalClosureSym(), TyVar, this->m_func),
6962+
localClosureOpnd,
69516963
this->m_func),
69526964
offset);
69536965

69546966
// Create a new local closure for the body when either body scope has scope slots allocated or
69556967
// eval is present which can leak declarations.
6956-
if (this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() > 0 || this->m_func->GetJITFunctionBody()->HasScopeObject())
6968+
if (this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() > 0 || this->m_func->GetJITFunctionBody()->HasScopeObject())
69576969
{
69586970
if (this->m_func->GetJITFunctionBody()->HasScopeObject())
69596971
{
@@ -6994,6 +7006,7 @@ IRBuilder::BuildEmpty(Js::OpCode newOpcode, uint32 offset)
69947006
lfd->isNonFastPathFrameDisplay = true;
69957007
}
69967008
break;
7009+
}
69977010

69987011
default:
69997012
this->AddInstr(instr, offset);

test/Bugs/rlexe.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,4 +496,9 @@
496496
<compile-flags>-force:deferparse -parserstatecache -useparserstatecache</compile-flags>
497497
</default>
498498
</test>
499+
<test>
500+
<default>
501+
<files>withSplitScope.js</files>
502+
</default>
503+
</test>
499504
</regress-exe>

test/Bugs/withSplitScope.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
function foo()
7+
{
8+
(function bar(a =
9+
(function()
10+
{
11+
with (1)
12+
{
13+
bar;
14+
}
15+
})()
16+
){})();
17+
}
18+
19+
foo();
20+
foo();
21+
foo();
22+
23+
WScript.Echo("Pass");

0 commit comments

Comments
 (0)