Skip to content

Commit c7f192a

Browse files
authored
Merge pull request #6684 from rhuanjl/fix_gen_proto
Handle corrupted generator or async generator prototype
2 parents a28fef1 + f69edb2 commit c7f192a

File tree

5 files changed

+62
-6
lines changed

5 files changed

+62
-6
lines changed

lib/Runtime/Library/JavascriptAsyncGeneratorFunction.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@ Var JavascriptAsyncGeneratorFunction::EntryAsyncGeneratorFunctionImplementation(
5050

5151
auto* asyncGeneratorFn = VarTo<JavascriptAsyncGeneratorFunction>(function);
5252
auto* library = scriptContext->GetLibrary();
53-
auto* prototype = VarTo<DynamicObject>(JavascriptOperators::GetPropertyNoCache(
54-
function, Js::PropertyIds::prototype, scriptContext));
53+
Var prototype = JavascriptOperators::GetPropertyNoCache(function, Js::PropertyIds::prototype, scriptContext);
54+
55+
// fall back to the original prototype if we have an invalid prototype object
56+
DynamicObject* protoObject = VarIs<DynamicObject>(prototype) ?
57+
UnsafeVarTo<DynamicObject>(prototype) : library->GetAsyncGeneratorPrototype();
58+
5559
auto* scriptFn = asyncGeneratorFn->GetGeneratorVirtualScriptFunction();
56-
auto* generator = library->CreateAsyncGenerator(args, scriptFn, prototype);
60+
auto* generator = library->CreateAsyncGenerator(args, scriptFn, protoObject);
5761

5862
// Run the generator to execute until the beginning of the body
5963
if (scriptFn->GetFunctionInfo()->GetGeneratorWithComplexParams())

lib/Runtime/Library/JavascriptGeneratorFunction.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,16 @@ using namespace Js;
112112
auto* library = scriptContext->GetLibrary();
113113
auto* generatorFunction = VarTo<JavascriptGeneratorFunction>(function);
114114

115-
DynamicObject* prototype = VarTo<DynamicObject>(JavascriptOperators::GetPropertyNoCache(
116-
function, Js::PropertyIds::prototype, scriptContext));
115+
Var prototype = JavascriptOperators::GetPropertyNoCache(function, Js::PropertyIds::prototype, scriptContext);
116+
117+
// fall back to the original prototype if we have an invalid prototype object
118+
DynamicObject* protoObject = VarIs<DynamicObject>(prototype) ?
119+
UnsafeVarTo<DynamicObject>(prototype) : library->GetGeneratorPrototype();
117120

118121
JavascriptGenerator* generator = library->CreateGenerator(
119122
args,
120123
generatorFunction->scriptFunction,
121-
prototype);
124+
protoObject);
122125

123126
// Call a next on the generator to execute till the beginning of the body
124127
FunctionInfo* funcInfo = generatorFunction->scriptFunction->GetFunctionInfo();

lib/Runtime/Library/JavascriptLibrary.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,9 @@ namespace Js
628628
DynamicObject* GetWebAssemblyLinkErrorPrototype() const { return webAssemblyLinkErrorPrototype; }
629629
DynamicObject* GetWebAssemblyLinkErrorConstructor() const { return webAssemblyLinkErrorConstructor; }
630630

631+
DynamicObject* GetAsyncGeneratorPrototype() const { return asyncGeneratorPrototype; }
632+
DynamicObject* GetGeneratorPrototype() const { return generatorPrototype; }
633+
631634
DynamicObject* GetChakraLib() const { return chakraLibraryObject; }
632635

633636
#if ENABLE_TTD

test/es6/generators-functionality.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56

@@ -56,6 +57,28 @@ function simpleThrowFunc() {
5657
var global = (function() { return this; }());
5758

5859
var tests = [
60+
{
61+
name: "Generator function with overwritten prototype",
62+
body: function () {
63+
function* gf() {};
64+
var gfp = gf.prototype;
65+
assert.strictEqual(gf().__proto__, gfp, "Generator function uses prototype.");
66+
var obj = {};
67+
gf.prototype = obj;
68+
assert.strictEqual(gf().__proto__, obj, "Generator function uses overwritten prototype.");
69+
gf.prototype = 1;
70+
assert.areEqual(gf().__proto__.toString(), gfp.toString(), "Generator function falls back to original prototype.");
71+
if (gf().__proto__ === gfp) { assert.error("Original prototype should not be same object as gfp")}
72+
var originalGfp = gf().__proto__;
73+
assert.strictEqual(gf().__proto__, originalGfp, "Generator function falls back to original prototype.");
74+
gf.prototype = 0;
75+
assert.strictEqual(gf().__proto__, originalGfp, "Generator function falls back to original prototype.");
76+
gf.prototype = "hi";
77+
assert.strictEqual(gf().__proto__, originalGfp, "Generator function falls back to original prototype.");
78+
delete gfp.prototype;
79+
assert.strictEqual(gf().__proto__, originalGfp, "Generator function falls back to original prototype.");
80+
}
81+
},
5982
{
6083
name: "Simple generator functions with no parameters or locals or captures",
6184
body: function () {

test/es7/async-generator-apis.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56

@@ -30,6 +31,28 @@ function testMethod(object, name, objectName, methodName = name) {
3031
}
3132

3233
const tests = [
34+
{
35+
name: "Async Generator function with overwritten prototype",
36+
body: function () {
37+
async function* agf() {};
38+
var gfp = agf.prototype;
39+
assert.strictEqual(agf().__proto__, gfp, "Async Generator function uses prototype.");
40+
var obj = {};
41+
agf.prototype = obj;
42+
assert.strictEqual(agf().__proto__, obj, "Async Generator function uses overwritten prototype.");
43+
agf.prototype = 1;
44+
assert.areEqual(agf().__proto__.toString(), gfp.toString(), "Generator function falls back to original prototype.");
45+
if (agf().__proto__ === gfp) { assert.error("Original prototype should not be same object as gfp")}
46+
var originalGfp = agf().__proto__;
47+
assert.strictEqual(agf().__proto__, originalGfp, "Async Generator function falls back to original prototype.");
48+
agf.prototype = 0;
49+
assert.strictEqual(agf().__proto__, originalGfp, "Async Generator function falls back to original prototype.");
50+
agf.prototype = "hi";
51+
assert.strictEqual(agf().__proto__, originalGfp, "Async Generator function falls back to original prototype.");
52+
delete gfp.prototype;
53+
assert.strictEqual(agf().__proto__, originalGfp, "Async Generator function falls back to original prototype.");
54+
}
55+
},
3356
{
3457
name: "AsyncGeneratorFunction is not exposed on the global object",
3558
body: function () {

0 commit comments

Comments
 (0)