From: Gabriel Ivăncescu gabrielopcode@gmail.com
Behavior depends on mode. Javascript used inside mshtml allows non-JS objects that expose "length" to be used in apply(). For ES5 and above, even JS objects that expose "length" are allowed. Javascript not in HTML mode does not, however.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/function.c | 126 ++++++++++++++++++++++++++++-- dlls/jscript/tests/api.js | 2 + dlls/mshtml/tests/documentmode.js | 66 ++++++++++++++++ 3 files changed, 187 insertions(+), 7 deletions(-)
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index ffb55af0922..14424e6661f 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -453,6 +453,109 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a return S_OK; }
+static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, jsval_t **ret) +{ + IDispatchEx *dispex; + DWORD length, i; + jsval_t *argv; + DISPID dispid; + EXCEPINFO ei; + UINT err = 0; + HRESULT hres; + VARIANT var; + BSTR name; + + if(!(name = SysAllocString(L"length"))) + return E_OUTOFMEMORY; + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres) && dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else { + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + dispex = NULL; + } + SysFreeString(name); + if(SUCCEEDED(hres) && dispid == DISPID_UNKNOWN) + hres = DISP_E_UNKNOWNNAME; + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, ctx->lcid, DISPATCH_PROPERTYGET, NULL, + &var, &ei, &ctx->jscaller->IServiceProvider_iface); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYGET, NULL, &var, &ei, &err); + if(FAILED(hres)) { + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(ctx, &ei); + if(hres == DISP_E_MEMBERNOTFOUND) + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + + if(FAILED(VariantChangeType(&var, &var, 0, VT_UI4))) { + VariantClear(&var); + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + length = V_UI4(&var); + + argv = malloc(length * sizeof(*argv)); + if(!argv) { + hres = E_OUTOFMEMORY; + goto fail; + } + + for(i = 0; i < length; i++) { + WCHAR buf[12]; + + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + if(!(name = SysAllocString(buf))) + hres = E_OUTOFMEMORY; + else { + if(dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + SysFreeString(name); + } + if(SUCCEEDED(hres)) { + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, ctx->lcid, DISPATCH_PROPERTYGET, NULL, + &var, &ei, &ctx->jscaller->IServiceProvider_iface); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYGET, NULL, &var, &ei, &err); + if(SUCCEEDED(hres)) { + hres = variant_to_jsval(ctx, &var, &argv[i]); + VariantClear(&var); + }else if(hres == DISP_E_EXCEPTION) { + handle_dispatch_exception(ctx, &ei); + } + } + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME || hres == DISP_E_MEMBERNOTFOUND) { + argv[i] = jsval_undefined(); + continue; + } + while(i--) + jsval_release(argv[i]); + free(argv); + goto fail; + } + } + + *argc = length; + *ret = argv; + hres = S_OK; +fail: + if(dispex) + IDispatchEx_Release(dispex); + return hres; +} + static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsval_t this_val = jsval_undefined(); @@ -484,22 +587,31 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
if(argc >= 2) { jsdisp_t *arg_array = NULL; + IDispatch *obj = NULL;
if(is_object_instance(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) )) { - jsdisp_release(arg_array); - arg_array = NULL; + obj = get_object(argv[1]); + arg_array = iface_to_jsdisp(obj); + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + if(!arg_array) { + if(!ctx->html_mode) + obj = NULL; + }else if(!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS)) { + jsdisp_release(arg_array); + arg_array = NULL; + obj = NULL; + } } }
if(arg_array) { hres = array_to_args(ctx, arg_array, &cnt, &args); jsdisp_release(arg_array); + }else if(obj) { + hres = disp_to_args(ctx, obj, &cnt, &args); }else { - FIXME("throw TypeError\n"); - hres = E_FAIL; + hres = JS_E_JSCRIPT_EXPECTED; } }
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index aea7cac63dc..8c054fff058 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2918,6 +2918,8 @@ testFunctionThis("toString"); testFunctionThis("call"); testFunctionThis("apply");
+testException(function() {(function (a, b) {}).apply(null, testObj)}, "E_JSCRIPT_EXPECTED"); + function testArrayHostThis(func) { testException(function() { Array.prototype[func].call(testObj); }, "E_JSCRIPT_EXPECTED"); } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 8e8b87d7e36..562761a022f 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -502,6 +502,72 @@ sync_test("builtin_obj", function() { f.call = function() { }; ok(f.apply === 0, "changed f.apply = ", f.apply); ok(f.call instanceof Function, "changed f.call not instance of Function"); + + e = Array.isArray(document.body.childNodes); + ok(e === false, "isArray(childNodes) returned " + e); + } + + (function(a, b, c) { + ok(a === document.body.childNodes[0], "a = " + a); + ok(b === document.body.childNodes[1], "b = " + b); + ok(c === document.body.childNodes[2], "c = " + c); + }).apply(null, document.body.childNodes); + + elem1[0] = "a"; + elem1[1] = "b"; + if(v < 9) { + try { + (function(a, b) {}).apply(null, elem1); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with elem without length] e = " + e); + }else { + (function(a, b) { + ok(a === undefined, "a = " + a); + ok(b === undefined, "b = " + b); + }).apply(null, elem1); + } + + elem1.length = 2; + (function(a, b) { + ok(a === "a", "a = " + a); + ok(b === "b", "b = " + b); + }).apply(null, elem1); + + elem1 = new Object; + elem1[0] = "c"; + elem1[1] = "d"; + if(v < 9) { + try { + (function(c, d) {}).apply(null, elem1); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object without length] e = " + e); + }else { + (function(c, d) { + ok(c === undefined, "c = " + c); + ok(d === undefined, "d = " + d); + }).apply(null, elem1); + } + + elem1.length = 2; + if(v < 9) { + try { + (function(c, d) {}).apply(null, elem1); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object with length] e = " + e); + }else { + (function(c, d) { + ok(c === "c", "c = " + c); + ok(d === "d", "d = " + d); + }).apply(null, elem1); } });
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/error.c | 1 + dlls/jscript/function.c | 8 ++++---- dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/documentmode.js | 3 --- 6 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 3ff40a1e1e7..a7513981676 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -489,6 +489,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_JSCRIPT_EXPECTED: case JS_E_ENUMERATOR_EXPECTED: case JS_E_REGEXP_EXPECTED: + case JS_E_ARRAY_OR_ARGS_EXPECTED: case JS_E_ARRAY_EXPECTED: case JS_E_CYCLIC_PROTO_VALUE: case JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE: diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 14424e6661f..e787758d31f 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -479,7 +479,7 @@ static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, hres = DISP_E_UNKNOWNNAME; if(FAILED(hres)) { if(hres == DISP_E_UNKNOWNNAME) - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; }
@@ -492,13 +492,13 @@ static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, if(hres == DISP_E_EXCEPTION) handle_dispatch_exception(ctx, &ei); if(hres == DISP_E_MEMBERNOTFOUND) - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; }
if(FAILED(VariantChangeType(&var, &var, 0, VT_UI4))) { VariantClear(&var); - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; } length = V_UI4(&var); @@ -611,7 +611,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi }else if(obj) { hres = disp_to_args(ctx, obj, &cnt, &args); }else { - hres = JS_E_JSCRIPT_EXPECTED; + hres = ctx->html_mode ? JS_E_ARRAY_OR_ARGS_EXPECTED : JS_E_JSCRIPT_EXPECTED; } }
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index a3009239ba1..38ba7e61a6f 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -565,6 +565,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_INVALID_URI_CHAR MAKE_JSERROR(IDS_URI_INVALID_CHAR) #define JS_E_FRACTION_DIGITS_OUT_OF_RANGE MAKE_JSERROR(IDS_FRACTION_DIGITS_OUT_OF_RANGE) #define JS_E_PRECISION_OUT_OF_RANGE MAKE_JSERROR(IDS_PRECISION_OUT_OF_RANGE) +#define JS_E_ARRAY_OR_ARGS_EXPECTED MAKE_JSERROR(IDS_ARRAY_OR_ARGS_EXPECTED) #define JS_E_INVALID_LENGTH MAKE_JSERROR(IDS_INVALID_LENGTH) #define JS_E_ARRAY_EXPECTED MAKE_JSERROR(IDS_ARRAY_EXPECTED) #define JS_E_CYCLIC_PROTO_VALUE MAKE_JSERROR(IDS_CYCLIC_PROTO_VALUE) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 3e46023adc6..998082a1046 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -69,6 +69,7 @@ STRINGTABLE IDS_URI_INVALID_CHAR "URI to be encoded contains invalid characters" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" IDS_PRECISION_OUT_OF_RANGE "Precision is out of range" + IDS_ARRAY_OR_ARGS_EXPECTED "Array or arguments object expected" IDS_INVALID_LENGTH "Array length must be a finite positive integer" IDS_ARRAY_EXPECTED "Array object expected" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 640cc01cff9..30147f683a0 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -67,6 +67,7 @@ #define IDS_URI_INVALID_CODING 0x13A1 #define IDS_FRACTION_DIGITS_OUT_OF_RANGE 0x13A2 #define IDS_PRECISION_OUT_OF_RANGE 0x13A3 +#define IDS_ARRAY_OR_ARGS_EXPECTED 0x13A4 #define IDS_INVALID_LENGTH 0x13A5 #define IDS_ARRAY_EXPECTED 0x13A7 #define IDS_INVALID_WRITABLE_PROP_DESC 0x13AC diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 562761a022f..3a9fb8319bb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -521,7 +521,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with elem without length] e = " + e); }else { (function(a, b) { @@ -545,7 +544,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object without length] e = " + e); }else { (function(c, d) { @@ -561,7 +559,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object with length] e = " + e); }else { (function(c, d) {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/array.c | 8 +++++- dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 2 +- dlls/jscript/tests/api.js | 1 + dlls/mshtml/tests/documentmode.js | 46 +++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index dfd9eda75cc..80fb52f486f 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -948,8 +948,14 @@ static HRESULT Array_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi TRACE("\n");
array = array_this(vthis); - if(!array) + if(!array) { + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + if(is_undefined(vthis) || is_null(vthis)) + return JS_E_OBJECT_EXPECTED; + return Object_toString(ctx, vthis, flags, argc, argv, r); + } return JS_E_ARRAY_EXPECTED; + }
return array_join(ctx, &array->dispex, array->length, L",", 1, to_string, r); } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 38ba7e61a6f..73d61b48f1b 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -494,6 +494,7 @@ HRESULT localize_number(script_ctx_t*,DOUBLE,BOOL,jsstr_t**); BOOL is_builtin_eval_func(jsdisp_t*); HRESULT builtin_eval(script_ctx_t*,struct _call_frame_t*,WORD,unsigned,jsval_t*,jsval_t*); HRESULT JSGlobal_eval(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); +HRESULT Object_toString(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); HRESULT Object_get_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); HRESULT Object_set_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*);
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index feeff5c294a..a1ba990695b 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -24,7 +24,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
-static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { const WCHAR *str = NULL; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 8c054fff058..9158e31fd8a 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2704,6 +2704,7 @@ testException(function() {date.setTime();}, "E_ARG_NOT_OPT"); testException(function() {date.setYear();}, "E_ARG_NOT_OPT"); testException(function() {arr.test();}, "E_NO_PROPERTY"); testException(function() {[1,2,3].sort(nullDisp);}, "E_JSCRIPT_EXPECTED"); +testException(function() {var o = new Object(); o.length = 1; o[0] = "a"; Array.prototype.toString.call(o);}, "E_NOT_ARRAY"); testException(function() {var o = new Object(); o.length = 1; o[0] = "a"; Array.prototype.toLocaleString.call(o);}, "E_NOT_ARRAY"); testException(function() {Number.prototype.toString.call(arr);}, "E_NOT_NUM"); testException(function() {Number.prototype.toFixed.call(arr);}, "E_NOT_NUM"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3a9fb8319bb..59801936ecd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -505,6 +505,52 @@ sync_test("builtin_obj", function() {
e = Array.isArray(document.body.childNodes); ok(e === false, "isArray(childNodes) returned " + e); + e = Array.prototype.toString.call(Number); + ok(e === "[object Function]", "Array.toString(Number) = " + e); + } + + function test_toString(msg, constr, err) { + var e = 0; + if(typeof(err) === "string") { + e = constr.prototype.toString.call(document.body); + ok(e === err, msg + ".toString(body) = " + e); + return; + } + try { + constr.prototype.toString.call(document.body); + }catch(ex) { + e = ex.number; + } + ok(e === err - 0x80000000, "[" + msg + ".toString(body)] e = " + e); + } + + test_toString("Array", Array, v < 9 ? 0xa13a7 : "[object HTMLBodyElement]"); + test_toString("Boolean", Boolean, 0xa1392); + test_toString("Date", Date, 0xa138e); + test_toString("RegExp", RegExp, 0xa1398); + test_toString("Number", Number, 0xa1389); + + if(v >= 9) { + var obj = { length: 2 }; + obj[0] = "foo"; + obj[1] = "bar"; + e = Array.prototype.toString.call(obj); + ok(e === "[object Object]", "Array.toString(array-like object) = " + e); + + obj = Object.create(null); + obj.length = 2; + obj[0] = "foo"; + obj[1] = "bar"; + e = Array.prototype.toString.call(obj); + ok(e === "[object Object]", "Array.toString(array-like object with no prototype) = " + e); + + e = 0; + try { + Array.prototype.toString.call(null); + }catch(ex) { + e = ex.number; + } + ok(e === 0xa138f - 0x80000000, "Array.toString(null) e = " + e); }
(function(a, b, c) {
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/jscript/string.c | 2 +- dlls/jscript/tests/api.js | 3 +++ dlls/mshtml/tests/documentmode.js | 1 + 7 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index a7513981676..9f22b7feefa 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -479,6 +479,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_MISSING_ARG: case JS_E_OBJECT_NOT_COLLECTION: case JS_E_FUNCTION_EXPECTED: + case JS_E_STRING_EXPECTED: case JS_E_DATE_EXPECTED: case JS_E_NUMBER_EXPECTED: case JS_E_OBJECT_EXPECTED: diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 73d61b48f1b..43486c3b753 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -548,6 +548,7 @@ static inline HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_ #define JS_E_DISABLED_CC MAKE_JSERROR(IDS_DISABLED_CC) #define JS_E_EXPECTED_AT MAKE_JSERROR(IDS_EXPECTED_AT) #define JS_E_FUNCTION_EXPECTED MAKE_JSERROR(IDS_NOT_FUNC) +#define JS_E_STRING_EXPECTED MAKE_JSERROR(IDS_NOT_STRING) #define JS_E_DATE_EXPECTED MAKE_JSERROR(IDS_NOT_DATE) #define JS_E_NUMBER_EXPECTED MAKE_JSERROR(IDS_NOT_NUM) #define JS_E_OBJECT_EXPECTED MAKE_JSERROR(IDS_OBJECT_EXPECTED) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 998082a1046..189f6fe19a3 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -51,6 +51,7 @@ STRINGTABLE IDS_DISABLED_CC "Conditional compilation is turned off" IDS_EXPECTED_AT "Expected '@'" IDS_NOT_FUNC "Function expected" + IDS_NOT_STRING "'[object]' is not a string object" IDS_NOT_DATE "'[object]' is not a date object" IDS_NOT_NUM "Number expected" IDS_OBJECT_EXPECTED "Object expected" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 30147f683a0..7b37a7ae8ea 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -49,6 +49,7 @@ #define IDS_DISABLED_CC 0x0406 #define IDS_EXPECTED_AT 0x0408 #define IDS_NOT_FUNC 0x138A +#define IDS_NOT_STRING 0x138D #define IDS_NOT_DATE 0x138E #define IDS_NOT_NUM 0x1389 #define IDS_OBJECT_EXPECTED 0x138F diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 42a2c697fbc..607dd7c0b65 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -89,7 +89,7 @@ static HRESULT stringobj_to_string(jsval_t vthis, jsval_t *r)
if(!(string = string_this(vthis))) { WARN("this is not a string object\n"); - return E_FAIL; + return JS_E_STRING_EXPECTED; }
if(r) diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 9158e31fd8a..a6ac3c7ed33 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2634,6 +2634,7 @@ var exception_array = { E_INVALID_LENGTH: { type: "RangeError", number: -2146823259 },
E_NOT_DATE: { type: "TypeError", number: -2146823282 }, + E_NOT_STRING: { type: "TypeError", number: -2146823283 }, E_NOT_BOOL: { type: "TypeError", number: -2146823278 }, E_ARG_NOT_OPT: { type: "TypeError", number: -2146827839 }, E_NO_PROPERTY: { type: "TypeError", number: -2146827850 }, @@ -2727,6 +2728,8 @@ testException(function() {(new Object()) instanceof nullDisp;}, "E_NOT_FUNC"); testException(function() {nullDisp instanceof Object;}, "E_OBJECT_EXPECTED"); testException(function() {Function.prototype.apply.call(nullDisp, Object, []);}, "E_OBJECT_REQUIRED"); testException(function() {Function.prototype.call.call(nullDisp, Object);}, "E_OBJECT_REQUIRED"); +testException(function() {String.prototype.toString.call(null);}, "E_NOT_STRING"); +testException(function() {String.prototype.toString.call([]);}, "E_NOT_STRING"); testException(function() {"test" in 3;}, "E_OBJECT_EXPECTED"); testException(function() {"test" in null;}, "E_OBJECT_EXPECTED"); testException(function() {"test" in nullDisp;}, "E_OBJECT_EXPECTED"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 59801936ecd..d671f43a1f5 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -529,6 +529,7 @@ sync_test("builtin_obj", function() { test_toString("Date", Date, 0xa138e); test_toString("RegExp", RegExp, 0xa1398); test_toString("Number", Number, 0xa1389); + test_toString("String", String, 0xa138d);
if(v >= 9) { var obj = { length: 2 };
Jacek Caban (@jacek) commented about dlls/jscript/function.c:
return E_OUTOFMEMORY;
- hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
- if(SUCCEEDED(hres) && dispex)
hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid);
- else {
hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid);
dispex = NULL;
- }
- SysFreeString(name);
- if(SUCCEEDED(hres) && dispid == DISPID_UNKNOWN)
hres = DISP_E_UNKNOWNNAME;
- if(FAILED(hres)) {
if(hres == DISP_E_UNKNOWNNAME)
hres = JS_E_JSCRIPT_EXPECTED;
goto fail;
- }
It seems that we could use a helper like `disp_propget_name` and maybe `disp_get_idx`. Below you open code things like dispatching exceptions, jsval conversion etc. I think it would be better to keep it for `dispex.c`. With those helpers, maybe we could just pass `IDispatch` to `array_to_args` instead of duplicating it.
Jacek Caban (@jacek) commented about dlls/jscript/function.c:
hres = JS_E_JSCRIPT_EXPECTED;
goto fail;
- }
- if(FAILED(VariantChangeType(&var, &var, 0, VT_UI4))) {
VariantClear(&var);
hres = JS_E_JSCRIPT_EXPECTED;
goto fail;
- }
- length = V_UI4(&var);
- argv = malloc(length * sizeof(*argv));
- if(!argv) {
hres = E_OUTOFMEMORY;
goto fail;
- }
Tests hang on 64-bit build when trying to apply -1 length. I didn't look deeper, but I suspect you're depending on allocation failure to handle that case.