Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Will be useful for mshtml proxy objects later, to show they don't behave like weird builtins on native.
dlls/mshtml/tests/es5.js | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 6e92fb6..c03a2c2 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -526,6 +526,16 @@ sync_test("defineProperty", function() { obj.no_setter = false; ok(obj.no_setter === true, "no_setter = " + obj.no_setter);
+ ok((delete obj.no_setter) === true, "delete no_setter returned false"); + ok(!("no_setter" in obj), "no_setter still in obj after delete"); + + Object.defineProperty(child.prototype, "no_setter", desc); + test_accessor_prop_desc(child.prototype, "no_setter", desc); + ok(!obj.hasOwnProperty("no_setter"), "no_setter is a property of obj"); + obj.no_setter = false; + ok(obj.no_setter === true, "no_setter = " + obj.no_setter); + ok(!obj.hasOwnProperty("no_setter"), "no_setter is a property of obj"); + /* call prop with getter */ desc = { get: function() {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Most of the existing code deals with NULL objects already and has proper checks, but some does not. Not only is this inconsistent, but it makes no sense to crash. For example, FFXIV Launcher uses instanceof on a NULL obj, but there's many other areas that need handling as well. This should fix them all, hopefully.
dlls/jscript/array.c | 8 ++++---- dlls/jscript/bool.c | 2 +- dlls/jscript/date.c | 2 +- dlls/jscript/dispex.c | 2 +- dlls/jscript/engine.c | 10 +++++----- dlls/jscript/enumerator.c | 4 ++-- dlls/jscript/error.c | 2 +- dlls/jscript/function.c | 8 ++++---- dlls/jscript/json.c | 2 +- dlls/jscript/jsregexp.c | 6 +++--- dlls/jscript/jsutils.c | 4 ++-- dlls/jscript/number.c | 2 +- dlls/jscript/object.c | 18 +++++++++--------- dlls/jscript/set.c | 2 +- dlls/jscript/string.c | 12 ++++++------ dlls/jscript/vbarray.c | 2 +- 16 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 9b97ef2..abfc997 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -39,7 +39,7 @@ static inline ArrayInstance *array_from_jsdisp(jsdisp_t *jsdisp)
static inline ArrayInstance *array_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_ARRAY)) ? array_from_jsdisp(jsdisp) : NULL; }
@@ -207,7 +207,7 @@ static HRESULT Array_concat(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign DWORD i;
for(i=0; i < argc; i++) { - if(is_object_instance(argv[i])) + if(is_object_instance(argv[i]) && get_object(argv[i])) hres = concat_obj(ret, get_object(argv[i]), &len); else hres = jsdisp_propput_idx(ret, len++, argv[i]); @@ -690,7 +690,7 @@ static HRESULT Array_sort(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned return hres;
if(argc >= 1) { - if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { if(argc > 1 && ctx->version < SCRIPTLANGUAGEVERSION_ES5) { WARN("invalid arg_cnt %d\n", argc); hres = JS_E_JSCRIPT_EXPECTED; @@ -1345,7 +1345,7 @@ static HRESULT ArrayConstr_isArray(script_ctx_t *ctx, jsval_t vthis, WORD flags,
TRACE("\n");
- if(!argc || !is_object_instance(argv[0])) { + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { if(r) *r = jsval_bool(FALSE); return S_OK; } diff --git a/dlls/jscript/bool.c b/dlls/jscript/bool.c index a230855..39206b4 100644 --- a/dlls/jscript/bool.c +++ b/dlls/jscript/bool.c @@ -41,7 +41,7 @@ static inline HRESULT boolval_this(jsval_t vthis, BOOL *ret) jsdisp_t *jsdisp; if(is_bool(vthis)) *ret = get_bool(vthis); - else if(is_object_instance(vthis) && (jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_BOOLEAN)) + else if(is_object_instance(vthis) && get_object(vthis) && (jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_BOOLEAN)) *ret = bool_from_jsdisp(jsdisp)->val; else return JS_E_BOOLEAN_EXPECTED; diff --git a/dlls/jscript/date.c b/dlls/jscript/date.c index e482c4a..c553f24 100644 --- a/dlls/jscript/date.c +++ b/dlls/jscript/date.c @@ -51,7 +51,7 @@ static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
static inline DateInstance *date_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_DATE)) ? date_from_jsdisp(jsdisp) : NULL; }
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index df2f65f..b9ad882 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -99,7 +99,7 @@ static inline BOOL is_function_prop(dispex_prop_t *prop) { BOOL ret = FALSE;
- if (is_object_instance(prop->u.val)) + if (is_object_instance(prop->u.val) && get_object(prop->u.val)) { jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val));
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index d894fbc..925eaeb 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -320,7 +320,7 @@ static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsig case EXPRVAL_STACK_REF: { jsval_t v = ctx->stack[ref->u.off];
- if(!is_object_instance(v)) { + if(!is_object_instance(v) || !get_object(v)) { FIXME("invoke %s\n", debugstr_jsval(v)); return E_FAIL; } @@ -1381,7 +1381,7 @@ static HRESULT interp_call(script_ctx_t *ctx) TRACE("%d %d\n", argn, do_ret);
obj = stack_topn(ctx, argn); - if(!is_object_instance(obj)) + if(!is_object_instance(obj) || !get_object(obj)) return JS_E_INVALID_PROPERTY;
clear_acc(ctx); @@ -1831,7 +1831,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) v = stack_pop(ctx);
if(is_object_instance(prot)) { - if(is_object_instance(v)) + if(is_object_instance(v) && get_object(v)) tmp = iface_to_jsdisp(get_object(v)); for(iter = tmp; !ret && iter; iter = iter->prototype) { hres = disp_cmp(get_object(prot), to_disp(iter), &ret); @@ -2985,7 +2985,7 @@ static HRESULT unwind_exception(script_ctx_t *ctx, HRESULT exception_hres) jsval_t msg;
WARN("Exception %08lx %s", exception_hres, debugstr_jsval(ei->valid_value ? ei->value : jsval_undefined())); - if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT) { + if(ei->valid_value && jsval_type(ei->value) == JSV_OBJECT && get_object(ei->value)) { error_obj = to_jsdisp(get_object(ei->value)); if(error_obj) { hres = jsdisp_propget_name(error_obj, L"message", &msg); @@ -3114,7 +3114,7 @@ static HRESULT bind_event_target(script_ctx_t *ctx, function_code_t *func, jsdis if(FAILED(hres)) return hres;
- if(!is_object_instance(v)) { + if(!is_object_instance(v) || !get_object(v)) { FIXME("Can't bind to %s\n", debugstr_jsval(v)); jsval_release(v); } diff --git a/dlls/jscript/enumerator.c b/dlls/jscript/enumerator.c index 0fc6750..e435e3a 100644 --- a/dlls/jscript/enumerator.c +++ b/dlls/jscript/enumerator.c @@ -40,7 +40,7 @@ static inline EnumeratorInstance *enumerator_from_jsdisp(jsdisp_t *jsdisp)
static inline EnumeratorInstance *enumerator_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_ENUMERATOR)) ? enumerator_from_jsdisp(jsdisp) : NULL; }
@@ -229,7 +229,7 @@ static HRESULT create_enumerator(script_ctx_t *ctx, jsval_t *argv, jsdisp_t **re { VARIANT varresult;
- if (!is_object_instance(*argv)) + if (!is_object_instance(*argv) || !get_object(*argv)) { FIXME("I don't know how to handle this type!\n"); return E_NOTIMPL; diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index d309d42..a1b182c 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -39,7 +39,7 @@ static HRESULT Error_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags,
TRACE("\n");
- if(is_object_instance(vthis)) + if(is_object_instance(vthis) && get_object(vthis)) jsthis = to_jsdisp(get_object(vthis)); else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) return JS_E_OBJECT_EXPECTED; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index fc8a85c..1b87f04 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -79,7 +79,7 @@ static inline FunctionInstance *function_from_jsdisp(jsdisp_t *jsdisp)
static inline FunctionInstance *function_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_FUNCTION)) ? function_from_jsdisp(jsdisp) : NULL; }
@@ -336,7 +336,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
TRACE("\n");
- if(!is_object_instance(vthis) || (!(function = function_this(vthis)) && to_jsdisp(get_object(vthis)))) + if(!is_object_instance(vthis) || !get_object(vthis) || (!(function = function_this(vthis)) && to_jsdisp(get_object(vthis)))) return JS_E_FUNCTION_EXPECTED;
if(argc) { @@ -356,7 +356,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi if(argc >= 2) { jsdisp_t *arg_array = NULL;
- if(is_object_instance(argv[1])) { + if(is_object_instance(argv[1]) && get_object(argv[1])) { arg_array = iface_to_jsdisp(get_object(argv[1])); if(arg_array && (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) { @@ -449,7 +449,7 @@ static HRESULT Function_bind(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig return E_NOTIMPL; }
- if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { bound_this = get_object(argv[0]); }else if(!is_null(argv[0])) { FIXME("%s is not an object instance\n", debugstr_jsval(argv[0])); diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index e0867eb..64d77a2 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -721,7 +721,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na case JSV_OBJECT: { jsdisp_t *obj;
- obj = iface_to_jsdisp(get_object(value)); + obj = get_object(value) ? iface_to_jsdisp(get_object(value)) : NULL; if(!obj) { hres = S_FALSE; break; diff --git a/dlls/jscript/jsregexp.c b/dlls/jscript/jsregexp.c index 15ebb11..6696586 100644 --- a/dlls/jscript/jsregexp.c +++ b/dlls/jscript/jsregexp.c @@ -41,7 +41,7 @@ static inline RegExpInstance *regexp_from_jsdisp(jsdisp_t *jsdisp)
static inline RegExpInstance *regexp_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_REGEXP)) ? regexp_from_jsdisp(jsdisp) : NULL; }
@@ -645,7 +645,7 @@ HRESULT create_regexp_var(script_ctx_t *ctx, jsval_t src_arg, jsval_t *flags_arg jsstr_t *src; HRESULT hres = S_OK;
- if(is_object_instance(src_arg)) { + if(is_object_instance(src_arg) && get_object(src_arg)) { jsdisp_t *obj;
obj = iface_to_jsdisp(get_object(src_arg)); @@ -892,7 +892,7 @@ static HRESULT RegExpConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, switch(flags) { case DISPATCH_METHOD: if(argc) { - if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { jsdisp_t *jsdisp = iface_to_jsdisp(get_object(argv[0])); if(jsdisp) { if(is_class(jsdisp, JSCLASS_REGEXP)) { diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 6bc34da..b0a920b 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -419,7 +419,7 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) jsdisp_release(jsdisp); *ret = prim; return S_OK; - }else { + }else if(get_object(prim)) { IDispatch_Release(get_object(prim)); } } @@ -435,7 +435,7 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint) jsdisp_release(jsdisp); *ret = prim; return S_OK; - }else { + }else if(get_object(prim)) { IDispatch_Release(get_object(prim)); } } diff --git a/dlls/jscript/number.c b/dlls/jscript/number.c index 472acd0..830c053 100644 --- a/dlls/jscript/number.c +++ b/dlls/jscript/number.c @@ -44,7 +44,7 @@ static inline HRESULT numberval_this(jsval_t vthis, DOUBLE *ret) jsdisp_t *jsdisp; if(is_number(vthis)) *ret = get_number(vthis); - else if(is_object_instance(vthis) && (jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_NUMBER)) + else if(is_object_instance(vthis) && get_object(vthis) && (jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_NUMBER)) *ret = number_from_jsdisp(jsdisp)->value; else return JS_E_NUMBER_EXPECTED; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index f8f1407..f375491 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -273,7 +273,7 @@ static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flags goto done;
if(argc && (jsthis = to_jsdisp(disp)) && is_object_instance(argv[0]) && - (jsdisp = to_jsdisp(get_object(argv[0])))) { + get_object(argv[0]) && (jsdisp = to_jsdisp(get_object(argv[0])))) { while(jsdisp->prototype) { if(jsdisp->prototype == jsthis) { ret = TRUE; @@ -332,13 +332,13 @@ HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned *r = jsval_undefined(); return S_OK; } - if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + if(!is_object_instance(vthis) || !get_object(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) goto done;
if(is_null(argv[0])) { proto = NULL; }else if(is_object_instance(argv[0])) { - proto = to_jsdisp(get_object(argv[0])); + proto = get_object(argv[0]) ? to_jsdisp(get_object(argv[0])) : NULL; if(!proto) { FIXME("Host object value\n"); return E_FAIL; @@ -476,7 +476,7 @@ static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, pro hres = E_FAIL; }else { /* FIXME: Check IsCallable */ - desc->getter = to_jsdisp(get_object(v)); + desc->getter = get_object(v) ? to_jsdisp(get_object(v)) : NULL; if(!desc->getter) FIXME("getter is not JS object\n"); } @@ -500,7 +500,7 @@ static HRESULT to_property_descriptor(script_ctx_t *ctx, jsdisp_t *attr_obj, pro hres = E_FAIL; }else { /* FIXME: Check IsCallable */ - desc->setter = to_jsdisp(get_object(v)); + desc->setter = get_object(v) ? to_jsdisp(get_object(v)) : NULL; if(!desc->setter) FIXME("setter is not JS object\n"); } @@ -587,7 +587,7 @@ static HRESULT Object_defineProperty(script_ctx_t *ctx, jsval_t vthis, WORD flag
TRACE("\n");
- if(argc < 1 || !is_object_instance(argv[0])) + if(argc < 1 || !is_object_instance(argv[0]) || !get_object(argv[0])) return JS_E_OBJECT_EXPECTED; obj = to_jsdisp(get_object(argv[0])); if(!obj) { @@ -599,7 +599,7 @@ static HRESULT Object_defineProperty(script_ctx_t *ctx, jsval_t vthis, WORD flag if(FAILED(hres)) return hres;
- if(argc >= 3 && is_object_instance(argv[2])) { + if(argc >= 3 && is_object_instance(argv[2]) && get_object(argv[2])) { attr_obj = to_jsdisp(get_object(argv[2])); if(attr_obj) { hres = to_property_descriptor(ctx, attr_obj, &prop_desc); @@ -655,7 +655,7 @@ static HRESULT Object_getOwnPropertyDescriptor(script_ctx_t *ctx, jsval_t vthis,
TRACE("\n");
- if(argc < 1 || !is_object_instance(argv[0])) + if(argc < 1 || !is_object_instance(argv[0]) || !get_object(argv[0])) return JS_E_OBJECT_EXPECTED; obj = to_jsdisp(get_object(argv[0])); if(!obj) { @@ -751,7 +751,7 @@ static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flag { jsdisp_t *obj;
- if(!argc || !is_object_instance(argv[0])) { + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { FIXME("invalid arguments\n"); return E_NOTIMPL; } diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 35edcf8..6e2e017 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -182,7 +182,7 @@ static HRESULT get_map_this(jsval_t vthis, MapInstance **ret)
if(!is_object_instance(vthis)) return JS_E_OBJECT_EXPECTED; - if(!(jsdisp = to_jsdisp(get_object(vthis))) || !is_class(jsdisp, JSCLASS_MAP)) { + if(!get_object(vthis) || !(jsdisp = to_jsdisp(get_object(vthis))) || !is_class(jsdisp, JSCLASS_MAP)) { WARN("not a Map object passed as 'this'\n"); return JS_E_MAP_EXPECTED; } diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 0b2e695..74dd061 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -38,7 +38,7 @@ static inline StringInstance *string_from_jsdisp(jsdisp_t *jsdisp)
static inline StringInstance *string_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_STRING)) ? string_from_jsdisp(jsdisp) : NULL; }
@@ -580,7 +580,7 @@ static HRESULT String_match(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign return S_OK; }
- if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); @@ -743,7 +743,7 @@ static HRESULT String_replace(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi return S_OK; }
- if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); @@ -760,7 +760,7 @@ static HRESULT String_replace(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi }
if(argc >= 2) { - if(is_object_instance(argv[1])) { + if(is_object_instance(argv[1]) && get_object(argv[1])) { rep_func = iface_to_jsdisp(get_object(argv[1])); if(rep_func && !is_class(rep_func, JSCLASS_FUNCTION)) { jsdisp_release(rep_func); @@ -959,7 +959,7 @@ static HRESULT String_search(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig return S_OK; }
- if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp && !is_class(regexp, JSCLASS_REGEXP)) { jsdisp_release(regexp); @@ -1116,7 +1116,7 @@ static HRESULT String_split(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign } }
- if(is_object_instance(argv[0])) { + if(is_object_instance(argv[0]) && get_object(argv[0])) { regexp = iface_to_jsdisp(get_object(argv[0])); if(regexp) { if(!is_class(regexp, JSCLASS_REGEXP)) { diff --git a/dlls/jscript/vbarray.c b/dlls/jscript/vbarray.c index 881c45e..6f35586 100644 --- a/dlls/jscript/vbarray.c +++ b/dlls/jscript/vbarray.c @@ -35,7 +35,7 @@ static inline VBArrayInstance *vbarray_from_jsdisp(jsdisp_t *jsdisp)
static inline VBArrayInstance *vbarray_this(jsval_t vthis) { - jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + jsdisp_t *jsdisp = is_object_instance(vthis) && get_object(vthis) ? to_jsdisp(get_object(vthis)) : NULL; return (jsdisp && is_class(jsdisp, JSCLASS_VBARRAY)) ? vbarray_from_jsdisp(jsdisp) : NULL; }
Hi Gabriel,
On 3/22/22 16:41, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescugabrielopcode@gmail.com
Most of the existing code deals with NULL objects already and has proper checks, but some does not. Not only is this inconsistent, but it makes no sense to crash. For example, FFXIV Launcher uses instanceof on a NULL obj, but there's many other areas that need handling as well. This should fix them all, hopefully.
dlls/jscript/array.c | 8 ++++---- dlls/jscript/bool.c | 2 +- dlls/jscript/date.c | 2 +- dlls/jscript/dispex.c | 2 +- dlls/jscript/engine.c | 10 +++++----- dlls/jscript/enumerator.c | 4 ++-- dlls/jscript/error.c | 2 +- dlls/jscript/function.c | 8 ++++---- dlls/jscript/json.c | 2 +- dlls/jscript/jsregexp.c | 6 +++--- dlls/jscript/jsutils.c | 4 ++-- dlls/jscript/number.c | 2 +- dlls/jscript/object.c | 18 +++++++++--------- dlls/jscript/set.c | 2 +- dlls/jscript/string.c | 12 ++++++------ dlls/jscript/vbarray.c | 2 +- 16 files changed, 43 insertions(+), 43 deletions(-)
This really could use some tests. You can grep for nullDisp for examples of such tests.
In general, I'm hoping that we could have a better solution. See the attached patch for a draft of possible solution that stores NULL VT_DISPATCH as JS null, which seems to match how we should treat it in majority cases. On top of that, we could get rid of all those NULL checks. It passes current tests, but more tests would be interesting.
Thanks,
Jacek
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 47 +++++++++++++++++ dlls/mshtml/tests/documentmode.js | 88 +++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index f375491..5045db3 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -289,6 +289,52 @@ done: return hres; }
+static HRESULT Object_defineGetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t desc; + const WCHAR *name; + jsstr_t *name_str; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + if(!is_object_instance(vthis) || !get_object(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + goto done; + + hres = to_flat_string(ctx, argc ? argv[0] : jsval_undefined(), &name_str, &name); + if(FAILED(hres)) + return hres; + + if(argc < 2 || !is_object_instance(argv[1]) || !get_object(argv[1])) + hres = JS_E_FUNCTION_EXPECTED; + else { + hres = S_OK; + desc.getter = to_jsdisp(get_object(argv[1])); + if(!desc.getter) { + FIXME("getter is not JS object\n"); + hres = E_NOTIMPL; + } + /* FIXME: Check IsCallable */ + } + + if(SUCCEEDED(hres)) { + desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = TRUE; + desc.explicit_setter = FALSE; + desc.explicit_value = FALSE; + desc.setter = NULL; + hres = jsdisp_define_property(jsthis, name, &desc); + } + jsstr_release(name_str); + if(FAILED(hres)) + return hres; +done: + if(r) + *r = jsval_undefined(); + return S_OK; +} + HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -360,6 +406,7 @@ static void Object_destructor(jsdisp_t *dispex) }
static const builtin_prop_t Object_props[] = { + {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2}, {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1}, {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1}, {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 2902902..18dd65e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1415,6 +1415,94 @@ sync_test("__proto__", function() { } });
+sync_test("__defineGetter__", function() { + var v = document.documentMode; + var r, x = 42; + + if(v < 11) { + ok(x.__defineGetter__ === undefined, "x.__defineGetter__ = " + x.__defineGetter__); + ok(!("__defineGetter__" in Object), "Object.__defineGetter__ = " + Object.__defineGetter__); + return; + } + ok(Object.prototype.hasOwnProperty("__defineGetter__"), "__defineGetter__ is not a property of Object.prototype"); + ok(Object.prototype.__defineGetter__.length === 2, "__defineGetter__.length = " + Object.prototype.__defineGetter__.length); + + function getter() { return "wine"; } + function setter(val) { } + + r = x.__defineGetter__("foo", getter); + ok(r === undefined, "__defineGetter__ on 42 returned " + r); + ok(x.foo === undefined, "42.foo = " + x.foo); + + x = {}; + r = x.__defineGetter__("foo", getter); + ok(r === undefined, "__defineGetter__ returned " + r); + ok(x.foo === "wine", "x.foo = " + x.foo); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo value = " + r.value); + ok(r.get === getter, "x.foo get = " + r.get); + ok(r.set === undefined, "x.foo set = " + r.set); + ok(r.writable === undefined, "x.foo writable = " + r.writable); + ok(r.enumerable === true, "x.foo enumerable = " + r.enumerable); + ok(r.configurable === true, "x.foo configurable = " + r.configurable); + + Object.defineProperty(x, "foo", { get: undefined, set: setter, configurable: false }); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo setter value = " + r.value); + ok(r.get === undefined, "x.foo setter get = " + r.get); + ok(r.set === setter, "x.foo setter set = " + r.set); + ok(r.writable === undefined, "x.foo setter writable = " + r.writable); + ok(r.enumerable === true, "x.foo setter enumerable = " + r.enumerable); + ok(r.configurable === false, "x.foo setter configurable = " + r.configurable); + try { + x.__defineGetter__("foo", getter); + ok(false, "expected exception calling __defineGetter__ on non-configurable property"); + }catch(e) { + ok(e.number === 0xa13d6 - 0x80000000, "__defineGetter__ on non-configurable property threw exception " + e.number); + } + + r = Object.prototype.__defineGetter__.call(undefined, "bar", getter); + ok(r === undefined, "__defineGetter__ on undefined returned " + r); + r = Object.prototype.__defineGetter__.call(null, "bar", getter); + ok(r === undefined, "__defineGetter__ on null returned " + r); + r = x.__defineGetter__(undefined, getter); + ok(r === undefined, "__defineGetter__ undefined prop returned " + r); + ok(x["undefined"] === "wine", "x.undefined = " + x["undefined"]); + r = x.__defineGetter__(false, getter); + ok(r === undefined, "__defineGetter__ undefined prop returned " + r); + ok(x["false"] === "wine", "x.false = " + x["false"]); + + try { + x.__defineGetter__("bar", "string"); + ok(false, "expected exception calling __defineGetter__ with string"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with string threw exception " + e.number); + } + try { + x.__defineGetter__("bar", undefined); + ok(false, "expected exception calling __defineGetter__ with undefined"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with undefined threw exception " + e.number); + } + try { + x.__defineGetter__("bar", null); + ok(false, "expected exception calling __defineGetter__ with null"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with null threw exception " + e.number); + } + try { + Object.prototype.__defineGetter__.call(x, "bar"); + ok(false, "expected exception calling __defineGetter__ with only one arg"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with only one arg threw exception " + e.number); + } + + x.bar = "test"; + ok(x.bar === "test", "x.bar = " + x.bar); + x.__defineGetter__("bar", getter); + ok(x.bar === "wine", "x.bar with getter = " + x.bar); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110992
Your paranoid android.
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647967723757 expected 1647967723809"
=== w10pro64 (testbot log) ===
WineRunTask.pl:error: The previous 1 run(s) terminated abnormally
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 47 +++++++++++++++ dlls/mshtml/tests/documentmode.js | 95 +++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 5045db3..8b0ec6f 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -335,6 +335,52 @@ done: return S_OK; }
+static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t desc; + const WCHAR *name; + jsstr_t *name_str; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + if(!is_object_instance(vthis) || !get_object(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + goto done; + + hres = to_flat_string(ctx, argc ? argv[0] : jsval_undefined(), &name_str, &name); + if(FAILED(hres)) + return hres; + + if(argc < 2 || !is_object_instance(argv[1]) || !get_object(argv[1])) + hres = JS_E_FUNCTION_EXPECTED; + else { + hres = S_OK; + desc.setter = to_jsdisp(get_object(argv[1])); + if(!desc.setter) { + FIXME("setter is not JS object\n"); + hres = E_NOTIMPL; + } + /* FIXME: Check IsCallable */ + } + + if(SUCCEEDED(hres)) { + desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = FALSE; + desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + desc.getter = NULL; + hres = jsdisp_define_property(jsthis, name, &desc); + } + jsstr_release(name_str); + if(FAILED(hres)) + return hres; +done: + if(r) + *r = jsval_undefined(); + return S_OK; +} + HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -407,6 +453,7 @@ static void Object_destructor(jsdisp_t *dispex)
static const builtin_prop_t Object_props[] = { {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2}, + {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2}, {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1}, {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1}, {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 18dd65e..4a776f8 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1503,6 +1503,101 @@ sync_test("__defineGetter__", function() { ok(x.bar === "wine", "x.bar with getter = " + x.bar); });
+sync_test("__defineSetter__", function() { + var v = document.documentMode; + var r, x = 42; + + if(v < 11) { + ok(x.__defineSetter__ === undefined, "x.__defineSetter__ = " + x.__defineSetter__); + ok(!("__defineSetter__" in Object), "Object.__defineSetter__ = " + Object.__defineSetter__); + return; + } + ok(Object.prototype.hasOwnProperty("__defineSetter__"), "__defineSetter__ is not a property of Object.prototype"); + ok(Object.prototype.__defineSetter__.length === 2, "__defineSetter__.length = " + Object.prototype.__defineSetter__.length); + + function getter() { return "wine"; } + function setter(val) { this.setterVal = val - 1; } + + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ on 42 returned " + r); + ok(x.foo === undefined, "42.foo = " + x.foo); + + x = {}; + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ returned " + r); + ok(x.setterVal === undefined, "x.setterVal = " + x.setterVal); + x.foo = 13; + ok(x.setterVal === 12, "x.setterVal = " + x.setterVal); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo value = " + r.value); + ok(r.get === undefined, "x.foo get = " + r.get); + ok(r.set === setter, "x.foo set = " + r.set); + ok(r.writable === undefined, "x.foo writable = " + r.writable); + ok(r.enumerable === true, "x.foo enumerable = " + r.enumerable); + ok(r.configurable === true, "x.foo configurable = " + r.configurable); + + Object.defineProperty(x, "foo", { get: getter, set: undefined, configurable: false }); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo getter value = " + r.value); + ok(r.get === getter, "x.foo getter get = " + r.get); + ok(r.set === undefined, "x.foo getter set = " + r.set); + ok(r.writable === undefined, "x.foo getter writable = " + r.writable); + ok(r.enumerable === true, "x.foo getter enumerable = " + r.enumerable); + ok(r.configurable === false, "x.foo getter configurable = " + r.configurable); + try { + x.__defineSetter__("foo", setter); + ok(false, "expected exception calling __defineSetter__ on non-configurable property"); + }catch(e) { + ok(e.number === 0xa13d6 - 0x80000000, "__defineSetter__ on non-configurable property threw exception " + e.number); + } + + r = Object.prototype.__defineSetter__.call(undefined, "bar", setter); + ok(r === undefined, "__defineSetter__ on undefined returned " + r); + r = Object.prototype.__defineSetter__.call(null, "bar", setter); + ok(r === undefined, "__defineSetter__ on null returned " + r); + r = x.__defineSetter__(null, setter); + ok(r === undefined, "__defineSetter__ null prop returned " + r); + x["null"] = 100; + ok(x.setterVal === 99, "x.setterVal after setting x.null = " + x.setterVal); + r = x.__defineSetter__(50, setter); + ok(r === undefined, "__defineSetter__ 50 prop returned " + r); + x["50"] = 33; + ok(x.setterVal === 32, "x.setterVal after setting x.50 = " + x.setterVal); + + try { + x.__defineSetter__("bar", true); + ok(false, "expected exception calling __defineSetter__ with bool"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with bool threw exception " + e.number); + } + try { + x.__defineSetter__("bar", undefined); + ok(false, "expected exception calling __defineSetter__ with undefined"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with undefined threw exception " + e.number); + } + try { + x.__defineSetter__("bar", null); + ok(false, "expected exception calling __defineSetter__ with null"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with null threw exception " + e.number); + } + try { + Object.prototype.__defineSetter__.call(x, "bar"); + ok(false, "expected exception calling __defineSetter__ with only one arg"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with only one arg threw exception " + e.number); + } + + x.bar = "test"; + ok(x.bar === "test", "x.bar = " + x.bar); + x.__defineSetter__("bar", setter); + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + x.bar = 10; + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + ok(x.setterVal === 9, "x.setterVal after setting bar = " + x.setterVal); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110993
Your paranoid android.
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647970426099 expected 1647970426153"
According to the ES6 spec, they don't throw anymore (compared to ES5), but native IE seems to not follow it here and throws anyway.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 18 ++++++------------ dlls/mshtml/tests/documentmode.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 8b0ec6f..cf823a3 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -845,10 +845,8 @@ static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flag { jsdisp_t *obj;
- if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { - FIXME("invalid arguments\n"); - return E_NOTIMPL; - } + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) + return JS_E_OBJECT_EXPECTED;
TRACE("(%s)\n", debugstr_jsval(argv[0]));
@@ -873,10 +871,8 @@ static HRESULT object_keys(script_ctx_t *ctx, jsval_t arg, enum jsdisp_enum_type jsstr_t *key; HRESULT hres;
- if(!is_object_instance(arg) || !get_object(arg)) { - FIXME("invalid arguments %s\n", debugstr_jsval(arg)); - return E_NOTIMPL; - } + if(!is_object_instance(arg) || !get_object(arg)) + return JS_E_OBJECT_EXPECTED;
obj = to_jsdisp(get_object(arg)); if(!obj) { @@ -932,10 +928,8 @@ static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD f { jsdisp_t *obj;
- if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { - FIXME("invalid arguments\n"); - return E_NOTIMPL; - } + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) + return JS_E_OBJECT_EXPECTED;
TRACE("(%s)\n", debugstr_jsval(argv[0]));
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 4a776f8..b4d0beb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1278,6 +1278,30 @@ sync_test("elem_attr", function() { } });
+sync_test("builtins_diffs", function() { + var v = document.documentMode; + + /* despite what spec says for ES6, IE still throws */ + var props = [ + "freeze", + "getPrototypeOf", + "isExtensible", + "isFrozen", + "isSealed", + "keys", + "preventExtensions", + "seal" + ]; + for(var i = 0; i < props.length; i++) { + try { + Object[props[i]]("test"); + ok(false, "Object." + props[i] + " with non-object: expected exception"); + }catch(e) { + ok(e.number === (v < 9 ? 0xa01b6 : 0xa138f) - 0x80000000, "Object." + props[i] + " with non-object: exception = " + e.number); + } + } +}); + sync_test("__proto__", function() { var v = document.documentMode; var r, x = 42;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110994
Your paranoid android.
=== w10pro64_ja (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
According to the ES6 spec, it should work in generic way for objects exposing "source" and "flags", but native IE seems to not follow it here and throws.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
FFXIV Launcher checks for this.
dlls/mshtml/tests/documentmode.js | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index b4d0beb..3f772cf 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1300,6 +1300,13 @@ sync_test("builtins_diffs", function() { ok(e.number === (v < 9 ? 0xa01b6 : 0xa138f) - 0x80000000, "Object." + props[i] + " with non-object: exception = " + e.number); } } + + try { + RegExp.prototype.toString.call({source: "foo", flags: "g"}); + ok(false, "RegExp.toString with non-regexp: expected exception"); + }catch(e) { + ok(e.number === 0xa1398 - 0x80000000, "RegExp.toString with non-regexp: exception = " + e.number); + } });
sync_test("__proto__", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110995
Your paranoid android.
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647973073885 expected 1647973073936"
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 7 +------ dlls/mshtml/tests/es5.js | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index cf823a3..7c952eb 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -851,13 +851,8 @@ static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flag TRACE("(%s)\n", debugstr_jsval(argv[0]));
obj = to_jsdisp(get_object(argv[0])); - if(!obj) { - FIXME("Non-JS object\n"); - return E_NOTIMPL; - } - if(r) - *r = obj->prototype + *r = obj && obj->prototype ? jsval_obj(jsdisp_addref(obj->prototype)) : jsval_null(); return S_OK; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c03a2c2..0339d9b 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -803,6 +803,8 @@ sync_test("getPrototypeOf", function() { obj = Object.create(null); ok(!("toString" in obj), "toString is in obj"); ok(Object.getPrototypeOf(obj) === null, "Object.getPrototypeOf(obj) = " + Object.getPrototypeOf(obj)); + + ok(Object.getPrototypeOf(external) === null, "Object.getPrototypeOf(non-JS obj) = " + Object.getPrototypeOf(external)); });
sync_test("toString", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110996
Your paranoid android.
=== w1064_tsign (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_he (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_el (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647976068602 expected 1647976068659"
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tested in the next patch (we use the test_own_data_prop_desc helper to avoid redundancy, which also checks enumerable).
dlls/jscript/dispex.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index b9ad882..eb3193a 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2546,6 +2546,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: + case PROP_IDX: desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 17 ++++++++++++++++- dlls/mshtml/tests/es5.js | 28 +++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index eb3193a..3dac8d0 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -285,7 +285,10 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++) idx = idx*10 + (*ptr-'0'); if(!*ptr && idx < This->builtin_info->idx_length(This)) { - prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0); + unsigned flags = PROPF_ENUMERABLE; + if(This->builtin_info->idx_put) + flags |= PROPF_WRITABLE; + prop = alloc_prop(This, name, PROP_IDX, flags); if(!prop) return E_OUTOFMEMORY;
@@ -2444,6 +2447,18 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty HRESULT hres;
if(id == DISPID_STARTENUM) { + if(obj->builtin_info->idx_length) { + unsigned i = 0, len = obj->builtin_info->idx_length(obj); + WCHAR name[12]; + + for(i = 0; i < len; i++) { + swprintf(name, ARRAY_SIZE(name), L"%d", i); + hres = find_prop_name(obj, string_hash(name), name, &iter); + if(FAILED(hres)) + return hres; + } + } + if (enum_type == JSDISP_ENUM_ALL) { hres = fill_protrefs(obj); if(FAILED(hres)) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0339d9b..2f78ca8 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -654,12 +654,38 @@ sync_test("property_definitions", function() { });
sync_test("string_idx", function() { - var s = "foobar"; + var i, s = "foobar"; ok(s[0] === "f", "s[0] = " + s[0]); ok(s[5] === "r", "s[5] = " + s[5]); ok(s[6] === undefined, "s[6] = " + s[6]); ok((delete s[0]) === false, "delete s[0] returned true"); ok((delete s[6]) === true, "delete s[6] returned false"); + s[6] = "X"; + ok(s[6] === undefined, "s[6] = " + s[6]); + + s = new String(s); + test_own_data_prop_desc(s, "0", false, true, false); + test_own_data_prop_desc(s, "1", false, true, false); + ok(!Object.prototype.hasOwnProperty.call(s, "6"), "'6' is a property"); + + s[7] = "X"; + ok(s[7] === "X", "s[7] = " + s[7]); + ok(Object.prototype.hasOwnProperty.call(s, "7"), "'7' not a property"); + + Object.defineProperty(s, "8", {writable: false, enumerable: true, configurable: true, value: "Y"}); + ok(s[8] === "Y", "s[8] = " + s[8]); + ok(Object.prototype.hasOwnProperty.call(s, "8"), "'8' not a property"); + + String.prototype[9] = "Z"; + ok(s[9] === "Z", "s[9] = " + s[9]); + delete String.prototype[9]; + + i = 0; + for(var idx in s) { + ok(s[idx] === "foobar XY"[idx], "enum s[" + idx + "] = " + s[idx]); + i++; + } + ok(i === 8, "enum did " + i + " iterations"); });
sync_test("string_trim", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110998
Your paranoid android.
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w8 (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w8adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w864 (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w864 (64 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=110990
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647964921788 expected 1647964921845"
=== w7u_el (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1647965025947 expected 1647965025999"