Skip to content

Commit 9da0194

Browse files
aneeshdkMikeHolman
authored andcommitted
[CVE-2017-0152] MSFT: 10592731 : Issue with Function name capturing in param scope
In a function expression with name, where the name is captured in one of the param scope functions, if there is a function or var declaration with the same name as the function expression name we were marking the function expression name as shadowed. In non-eval case this causes issue because the name symbol won't get added to the body. This change is to fix it in such a way if the name is captured in the param scope then we split the param and body scope such that the name symbol is added to the param scope not body scope.
1 parent b75b9e8 commit 9da0194

3 files changed

Lines changed: 33 additions & 1 deletion

File tree

lib/Parser/Parse.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5198,6 +5198,19 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho
51985198
paramScope->SetCannotMergeWithBodyScope();
51995199
}
52005200
}
5201+
if (paramScope->GetCanMergeWithBodyScope() && !fDeclaration && pnodeFnc->sxFnc.pnodeName != nullptr)
5202+
{
5203+
Symbol* funcSym = pnodeFnc->sxFnc.pnodeName->sxVar.sym;
5204+
if (funcSym->GetPid()->GetTopRef()->GetFuncScopeId() > pnodeFnc->sxFnc.functionId)
5205+
{
5206+
// This is a function expression with name captured in the param scope. In non-eval, non-split cases the function
5207+
// name symbol is added to the body scope to make it accessible in the body. But if there is a function or var
5208+
// declaration with the same name in the body then adding to the body will fail. So in this case we have to add
5209+
// the name symbol to the param scope by splitting it.
5210+
paramScope->SetCannotMergeWithBodyScope();
5211+
}
5212+
}
5213+
52015214
}
52025215
}
52035216

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3319,6 +3319,7 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
33193319
{
33203320
// Emit bytecode to copy the initial values from param names to their corresponding body bindings.
33213321
// We have to do this after the rest param is marked as false for need declaration.
3322+
Symbol* funcSym = funcInfo->root->sxFnc.GetFuncSymbol();
33223323
paramScope->ForEachSymbol([&](Symbol* param) {
33233324
Symbol* varSym = funcInfo->GetBodyScope()->FindLocalSymbol(param->GetName());
33243325
Assert(varSym || pnode->sxFnc.pnodeName->sxVar.sym == param);
@@ -3327,7 +3328,9 @@ void ByteCodeGenerator::EmitOneFunction(ParseNode *pnode)
33273328
{
33283329
// Do not copy the arguments to the body if it is not used
33293330
}
3330-
else if (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister))
3331+
else if ((funcSym == nullptr || funcSym != param) // Do not copy the symbol over to body as the function expression symbol
3332+
// is expected to stay inside the function expression scope
3333+
&& (varSym && varSym->GetSymbolType() == STVariable && (varSym->IsInSlot(funcInfo) || varSym->GetLocation() != Js::Constants::NoRegister)))
33313334
{
33323335
// Simulating EmitPropLoad here. We can't directly call the method as we have to use the param scope specifically.
33333336
// Walking the scope chain is not possible at this time.

test/es6/default-splitscope.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,22 @@ var tests = [
159159
return a;
160160
}
161161
assert.areEqual(10, f11()(), "Recursive call to the function from the body scope returns the right value when eval is there in the body");
162+
163+
function f13() {
164+
var a = function jnvgfg(sfgnmj = function ccunlk() { jnvgfg(undefined, 1); }, b) {
165+
if (b) {
166+
assert.areEqual(undefined, jnvgfg, "This refers to the instance in the body and the value of the function expression is not copied over");
167+
}
168+
var jnvgfg = 10;
169+
if (!b) {
170+
sfgnmj();
171+
return 100;
172+
}
173+
};
174+
assert.areEqual(100, a(), "After the recursion the right value is returned by the split scoped function");
175+
};
176+
f13();
177+
162178
}
163179
},
164180
{

0 commit comments

Comments
 (0)