From 746f4b50e9c13c720162f3bcc8795b7ef772fbba Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Thu, 28 Oct 2010 12:27:49 +0200 Subject: QScriptValue::construct(): Don't crash if function throws non-Object If an exception occurs, we should ignore the result of JSC::construct() and return the exception value, even if the exception is not an object. This makes the behavior match the documentation: "Calling construct() can cause an exception to occur in the script engine; in that case, construct() returns the value that was thrown". Task-number: QTBUG-14801 Reviewed-by: Jedrzej Nowacki --- src/script/api/qscriptvalue.cpp | 13 ++++++++----- tests/auto/qscriptvalue/tst_qscriptvalue.cpp | 25 +++++++++++++++++++++++++ tests/auto/qscriptvalue/tst_qscriptvalue.h | 1 + 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index f6390bb..f494106 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -1736,10 +1736,12 @@ QScriptValue QScriptValue::construct(const QScriptValueList &args) JSC::JSValue savedException; QScriptEnginePrivate::saveException(exec, &savedException); - JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, jscArgs); + JSC::JSValue result; + JSC::JSObject *newObject = JSC::construct(exec, callee, constructType, constructData, jscArgs); if (exec->hadException()) { - result = JSC::asObject(exec->exception()); + result = exec->exception(); } else { + result = newObject; QScriptEnginePrivate::restoreException(exec, savedException); } return d->engine->scriptValueFromJSCValue(result); @@ -1796,11 +1798,12 @@ QScriptValue QScriptValue::construct(const QScriptValue &arguments) JSC::JSValue savedException; QScriptEnginePrivate::saveException(exec, &savedException); - JSC::JSObject *result = JSC::construct(exec, callee, constructType, constructData, applyArgs); + JSC::JSValue result; + JSC::JSObject *newObject = JSC::construct(exec, callee, constructType, constructData, applyArgs); if (exec->hadException()) { - if (exec->exception().isObject()) - result = JSC::asObject(exec->exception()); + result = exec->exception(); } else { + result = newObject; QScriptEnginePrivate::restoreException(exec, savedException); } return d->engine->scriptValueFromJSCValue(result); diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp index 83a3388..639df36 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp @@ -2739,6 +2739,31 @@ void tst_QScriptValue::construct() QVERIFY(!QScriptValue(QScriptValue::NullValue).construct().isValid()); } +void tst_QScriptValue::construct_constructorThrowsPrimitive() +{ + QScriptEngine eng; + QScriptValue fun = eng.evaluate("(function() { throw 123; })"); + QVERIFY(fun.isFunction()); + // construct(QScriptValueList) + { + QScriptValue ret = fun.construct(); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toNumber(), 123.0); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(ret.strictlyEquals(eng.uncaughtException())); + eng.clearExceptions(); + } + // construct(QScriptValue) + { + QScriptValue ret = fun.construct(eng.newArray()); + QVERIFY(ret.isNumber()); + QCOMPARE(ret.toNumber(), 123.0); + QVERIFY(eng.hasUncaughtException()); + QVERIFY(ret.strictlyEquals(eng.uncaughtException())); + eng.clearExceptions(); + } +} + void tst_QScriptValue::lessThan_old() { QScriptEngine eng; diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.h b/tests/auto/qscriptvalue/tst_qscriptvalue.h index 8bfaa6a..462749a 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.h +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.h @@ -219,6 +219,7 @@ private slots: void getSetScriptClass(); void call(); void construct(); + void construct_constructorThrowsPrimitive(); void castToPointer(); void prettyPrinter_data(); void prettyPrinter(); -- cgit v0.12