Gabriel Ivăncescu : jscript: Handle detached scope objects 'this' in all calls.

Alexandre Julliard julliard at winehq.org
Mon May 16 15:37:58 CDT 2022


Module: wine
Branch: master
Commit: 5007c4d72f512455c9ad9d3a76ddbccb62ae7d44
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=5007c4d72f512455c9ad9d3a76ddbccb62ae7d44

Author: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Date:   Mon May 16 19:18:40 2022 +0300

jscript: Handle detached scope objects 'this' in all calls.

Not just for interpreted functions.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/jscript/engine.c      | 33 +++++++++++++++++++++++----------
 dlls/jscript/tests/api.js  |  2 ++
 dlls/jscript/tests/lang.js |  3 +++
 dlls/mshtml/tests/es5.js   | 20 ++++++++++++++++++++
 4 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index 73b9d868e0c..7dce4fe5d79 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -314,9 +314,13 @@ static HRESULT exprval_propget(script_ctx_t *ctx, exprval_t *ref, jsval_t *r)
 
 static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
 {
+    jsdisp_t *jsdisp;
+    HRESULT hres;
+    jsval_t v;
+
     switch(ref->type) {
     case EXPRVAL_STACK_REF: {
-        jsval_t v = ctx->stack[ref->u.off];
+        v = ctx->stack[ref->u.off];
 
         if(!is_object_instance(v)) {
             FIXME("invoke %s\n", debugstr_jsval(v));
@@ -326,10 +330,24 @@ static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsig
         return disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
     }
     case EXPRVAL_IDREF:
+        /* ECMA-262 3rd Edition 11.2.3.7 / ECMA-262 5.1 Edition 11.2.3.6 *
+         * Don't treat scope object props as PropertyReferences.         */
+        if((jsdisp = to_jsdisp(ref->u.idref.disp)) && jsdisp->builtin_info->class == JSCLASS_NONE) {
+            hres = disp_propget(ctx, ref->u.idref.disp, ref->u.idref.id, &v);
+            if(FAILED(hres))
+                return hres;
+            if(!is_object_instance(v)) {
+                FIXME("invoke %s\n", debugstr_jsval(v));
+                hres = E_FAIL;
+            }else {
+                hres = disp_call_value(ctx, get_object(v), NULL, flags, argc, argv, r);
+            }
+            jsval_release(v);
+            return hres;
+        }
         return disp_call(ctx, ref->u.idref.disp, ref->u.idref.id, flags, argc, argv, r);
     case EXPRVAL_JSVAL: {
         IDispatch *obj;
-        HRESULT hres;
 
         hres = to_object(ctx, ref->u.val, &obj);
         if(SUCCEEDED(hres)) {
@@ -3300,16 +3318,11 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi
         }
     }
 
-    /* ECMA-262 3rd Edition    11.2.3.7 */
     if(this_obj) {
-        jsdisp_t *jsthis;
+        jsdisp_t *jsthis = to_jsdisp(this_obj);
 
-        jsthis = iface_to_jsdisp(this_obj);
-        if(jsthis) {
-            if(jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis->builtin_info->class == JSCLASS_NONE)
-                this_obj = NULL;
-            jsdisp_release(jsthis);
-        }
+        if(jsthis && jsthis->builtin_info->class == JSCLASS_GLOBAL)
+            this_obj = NULL;
     }
 
     if(ctx->call_ctx && (flags & EXEC_EVAL)) {
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index e81bbea2ae9..1368f399b50 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -2634,6 +2634,8 @@ testException(function() {null.toString();}, "E_OBJECT_EXPECTED");
 testException(function() {RegExp.prototype.toString.call(new Object());}, "E_REGEXP_EXPECTED");
 testException(function() {/a/.lastIndex();}, "E_NOT_FUNC");
 testException(function() {"a".length();}, "E_NOT_FUNC");
+testException(function() {((function() { var f = Number.prototype.toString; return (function() { return f(); }); })())();}, "E_NOT_NUM");
+testException(function() {((function() { var f = Object.prototype.hasOwnProperty; return (function() { return f("f"); }); })())();}, "E_OBJECT_EXPECTED");
 
 testException(function() { return arguments.callee(); }, "E_STACK_OVERFLOW");
 
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js
index cf08423766c..67e4576813b 100644
--- a/dlls/jscript/tests/lang.js
+++ b/dlls/jscript/tests/lang.js
@@ -310,6 +310,9 @@ argumentsTest();
     ok(callAsExprTest.arguments === null, "callAsExprTest.arguments = " + callAsExprTest.arguments);
 })(1,2);
 
+tmp = ((function() { var f = function() {return this}; return (function() { return f(); }); })())();
+ok(tmp === this, "detached scope function call this != global this");
+
 tmp = (function() {1;})();
 ok(tmp === undefined, "tmp = " + tmp);
 tmp = eval("1;");
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js
index 0f9df4cb8ea..19161998aeb 100644
--- a/dlls/mshtml/tests/es5.js
+++ b/dlls/mshtml/tests/es5.js
@@ -1791,6 +1791,26 @@ sync_test("let scope instances", function() {
     ok(f() == 2, "f() = " + f());
 });
 
+sync_test("substituted this", function() {
+    try {
+        ((function() { var f = Number.prototype.toString; return (function() { return f(); }); })())();
+    }catch(ex) {
+        var n = ex.number >>> 0;
+        ok(n === JS_E_NUMBER_EXPECTED, "Number.toString threw " + n);
+    }
+
+    var r = ((function() { var f = Object.prototype.toString; return (function() { return f(); }); })())();
+    todo_wine.
+    ok(r === "[object Undefined]", "detached scope Object.toString returned " + r);
+
+    var r = (function() { this.f = Object.prototype.toString; return this.f(); })();
+    todo_wine.
+    ok(r === "[object Window]", "Object.toString returned " + r);
+
+    var r = ((function() { return (function() { return this; }); })())();
+    ok(r === window, "detached scope this = " + r);
+});
+
 sync_test("functions scope", function() {
     function f(){ return 1; }
     function f(){ return 2; }




More information about the wine-cvs mailing list