Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
[Merge chakra-core/ChakraCore@7829651f00] [1.6>1.7] [MERGE #3328 @suwc]…
Browse files Browse the repository at this point in the history
… Fix Issue#3217: Reflect.construct permanently corrupts the invoked constructor

Merge pull request #3328 from suwc:build/suwc/Issue3217

With the optional newTarget argument, Reflect.construct has a legitimate
user case where cached constructor prototype mismatches prototype of
newly created object. Therefore it is necessary to tighten requirement for
sharing type by checking if constructor prototypes match.
Confirmed no perf impact.

Fixes #3328
  • Loading branch information
chakrabot authored and kfarnung committed Jul 21, 2017
1 parent 7b06d0f commit 6494fd0
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6255,7 +6255,7 @@ namespace Js
if (typeHandler->IsSharable())
{
#if DBG
bool cachedProtoCanBeCached;
bool cachedProtoCanBeCached = false;
Assert(type->GetPrototype() == JavascriptOperators::GetPrototypeObjectForConstructorCache(constructor, requestContext, cachedProtoCanBeCached));
Assert(cachedProtoCanBeCached);
Assert(type->GetScriptContext() == constructorCache->GetScriptContext());
Expand Down
10 changes: 7 additions & 3 deletions deps/chakrashim/core/lib/Runtime/Library/JavascriptFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,13 +938,15 @@ namespace Js
resultObject,
JavascriptFunction::Is(functionObj) && functionObj->GetScriptContext() == scriptContext ?
JavascriptFunction::FromVar(functionObj) :
nullptr);
nullptr,
overridingNewTarget != nullptr);
}

Var JavascriptFunction::FinishConstructor(
const Var constructorReturnValue,
Var newObject,
JavascriptFunction *const function)
JavascriptFunction *const function,
bool hasOverridingNewTarget)
{
Assert(constructorReturnValue);

Expand All @@ -954,7 +956,9 @@ namespace Js
newObject = constructorReturnValue;
}

if (function && function->GetConstructorCache()->NeedsUpdateAfterCtor())
// #3217: Cases with overriding newTarget are not what constructor cache is intended for;
// Bypass constructor cache to avoid prototype mismatch/confusion.
if (function && function->GetConstructorCache()->NeedsUpdateAfterCtor() && !hasOverridingNewTarget)
{
JavascriptOperators::UpdateNewScObjectCache(function, newObject, function->GetScriptContext());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ namespace Js
static Var CallRootFunctionInScript(JavascriptFunction* func, Arguments args);

static Var CallAsConstructor(Var v, Var overridingNewTarget, Arguments args, ScriptContext* scriptContext, const Js::AuxArray<uint32> *spreadIndices = nullptr);
static Var FinishConstructor(const Var constructorReturnValue, Var newObject, JavascriptFunction *const function);
static Var FinishConstructor(const Var constructorReturnValue, Var newObject, JavascriptFunction *const function, bool hasOverridingNewTarget = false);

#if DBG
static void CheckValidDebugThunk(ScriptContext* scriptContext, RecyclableObject *function);
Expand Down
12 changes: 12 additions & 0 deletions deps/chakrashim/core/test/es6/classes_bugfixes.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,18 @@ var tests = [
assert.areEqual('abc', result, "result == 'abc'");
}
},
{
name: "Issue3217: Reflect.construct permanently corrupts the invoked constructor",
body: function () {
function Base() {}
function Derived() {}
Derived.prototype = Object.create(Base.prototype);

assert.isFalse(new Base() instanceof Derived);
Reflect.construct(Base, [], Derived);
assert.isFalse(new Base() instanceof Derived);
}
},
{
name: "OS12503560: assignment to super[prop] not accessing base class property",
body: function () {
Expand Down

0 comments on commit 6494fd0

Please sign in to comment.