From: Gabriel Ivăncescu gabrielopcode@gmail.com
For ES5, the JS global object is "window", so any properties redefined on window will impact all the JS globals since it's the same object. This isn't just a matter of the window object "shadowing" the JS global object; deleting a JS global prop from window also deletes it from the JS global object.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 48 +++++++++++++++++++++++++++++++ dlls/jscript/engine.c | 4 +-- dlls/jscript/jscript.c | 11 ++++++- dlls/jscript/jscript.h | 1 + dlls/mshtml/script.c | 6 +++- dlls/mshtml/tests/documentmode.js | 2 -- 6 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 91fa2c00cf4..88b93debb10 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -3558,3 +3558,51 @@ IWineJSDispatchHost *get_host_dispatch(IDispatch *disp) IWineJSDispatchHost_GetOuterDispatch(host_obj->host_iface, &ret); return ret; } + +/* ECMA-262 5.1 Edition 15.1 */ +HRESULT set_js_globals(script_ctx_t *ctx, IDispatch *global) +{ + jsdisp_t *new_global = to_jsdisp(global), *old_global = ctx->global; + const builtin_prop_t *bprop, *bend; + dispex_prop_t *prop, *end, *dst; + HRESULT hres; + BOOL b; + + if(!new_global || new_global->builtin_info != &HostObject_info) + return S_OK; + + /* Make sure the builtin methods are created as functions so we can copy them */ + for(bprop = old_global->builtin_info->props, bend = bprop + old_global->builtin_info->props_cnt; bprop != bend; bprop++) { + hres = find_prop_name(old_global, string_hash(bprop->name), bprop->name, FALSE, NULL, &prop); + if(FAILED(hres)) + return hres; + } + + /* Copy the props */ + for(prop = old_global->props, end = prop + old_global->prop_cnt; prop != end; prop++) { + assert(prop->type == PROP_JSVAL || prop->type == PROP_ACCESSOR); + + if(!(dst = lookup_dispex_prop(new_global, prop->hash, prop->name, FALSE))) { + if(!(dst = alloc_prop(new_global, prop->name, PROP_DELETED, 0))) + return E_OUTOFMEMORY; + }else { + dst->flags |= PROPF_CONFIGURABLE; + delete_prop(new_global, dst, &b); + } + + dst->flags = prop->flags; + dst->type = prop->type; + if(prop->type == PROP_JSVAL) { + hres = jsval_copy(prop->u.val, &dst->u.val); + if(FAILED(hres)) + return hres; + }else { + dst->u.accessor.getter = prop->u.accessor.getter ? jsdisp_addref(prop->u.accessor.getter) : NULL; + dst->u.accessor.setter = prop->u.accessor.setter ? jsdisp_addref(prop->u.accessor.setter) : NULL; + } + } + + jsdisp_release(old_global); + ctx->global = jsdisp_addref(new_global); + return S_OK; +} diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index c95fcace84a..ef1682f670e 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -820,7 +820,7 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t HRESULT hres;
LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { - if(item->flags & SCRIPTITEM_GLOBALMEMBERS) { + if((item->flags & SCRIPTITEM_GLOBALMEMBERS) && item->disp != (IDispatch*)&ctx->global->IWineJSDispatch_iface) { hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id); if(SUCCEEDED(hres)) { if(ret) @@ -3512,7 +3512,7 @@ HRESULT exec_source(script_ctx_t *ctx, DWORD flags, bytecode_t *bytecode, functi if(this_obj) { jsdisp_t *jsthis = to_jsdisp(this_obj);
- if(jsthis && jsthis->builtin_info->class == JSCLASS_GLOBAL) + if(jsthis && (jsthis->builtin_info->class == JSCLASS_GLOBAL || jsthis == ctx->global)) this_obj = NULL; }
diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index c42109b4143..8b486787a31 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -912,6 +912,14 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, WARN("object does not implement IDispatch\n"); return hres; } + + if(!wcscmp(pstrName, L"window")) { + hres = set_js_globals(This->ctx, disp); + if(FAILED(hres)) { + IDispatch_Release(disp); + return hres; + } + } }
item = malloc(sizeof(*item)); @@ -949,6 +957,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR IDispatch **ppdisp) { JScript *This = impl_from_IActiveScript(iface); + IWineJSDispatchHost *host_disp; jsdisp_t *script_obj;
TRACE("(%p)->(%s %p)\n", This, debugstr_w(pstrItemName), ppdisp); @@ -968,7 +977,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR if(item->script_obj) script_obj = item->script_obj; }
- *ppdisp = to_disp(script_obj); + *ppdisp = (host_disp = get_host_dispatch(to_disp(script_obj))) ? (IDispatch*)host_disp : to_disp(script_obj); IDispatch_AddRef(*ppdisp); return S_OK; } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index e9207c231d8..4ebfa313a5a 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -242,6 +242,7 @@ HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*); HRESULT init_host_object(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,UINT32,IWineJSDispatch**); HRESULT init_host_constructor(script_ctx_t*,IWineJSDispatchHost*,IWineJSDispatch*,IWineJSDispatch**); +HRESULT set_js_globals(script_ctx_t*,IDispatch*);
HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*); HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 7ac26e63a3b..ee79565d7dd 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -1806,7 +1806,11 @@ BOOL find_global_prop(HTMLInnerWindow *window, const WCHAR *name, DWORD flags, S
hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_GetDispID(dispex, str, flags & (~fdexNameEnsure), ret_id); + /* Avoid looking into ourselves if we're the actual global object */ + if(dispex == (IDispatchEx*)&window->base.outer_window->IWineJSDispatchHost_iface) + hres = DISP_E_UNKNOWNNAME; + else + hres = IDispatchEx_GetDispID(dispex, str, flags & (~fdexNameEnsure), ret_id); IDispatchEx_Release(dispex); }else { FIXME("No IDispatchEx\n"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 306d65e5768..a360b5ecf72 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1380,7 +1380,6 @@ sync_test("delete_prop", function() { ok(r, "did not get an expected globalprop2 exception"); }else { ok(!r, "got an unexpected exception"); - todo_wine. ok(!("globalprop2" in obj), "globalprop2 is still in obj"); }
@@ -1404,7 +1403,6 @@ sync_test("delete_prop", function() { ok(obj.globalprop4, "globalprop4 = " + globalprop4); r = (delete globalprop4); ok(r, "delete returned " + r); - todo_wine. ok(!("globalprop4" in obj), "globalprop4 is still in obj"); });