QJSManagedValue: Throw TypeErrors when accessing null or undefined

Accessing properties of null or undefined is supposed to throw
TypeErrors in ECMAScript.

Change-Id: I4f05d56fa2f4d6767e582795bf39769a12df8019
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2021-02-25 12:24:10 +01:00
parent ae22e8d479
commit 2e4561d4e7
3 changed files with 47 additions and 3 deletions

View File

@ -774,9 +774,15 @@ bool QJSManagedValue::hasOwnProperty(const QString &name) const
*/
QJSValue QJSManagedValue::property(const QString &name) const
{
if (!d || d->isNullOrUndefined())
if (!d)
return QJSValue();
if (d->isNullOrUndefined()) {
QV4::ExecutionEngine *e = v4Engine(d);
e->throwTypeError(QStringLiteral("Cannot read property '%1' of null").arg(name));
return QJSValue();
}
if (QV4::String *string = d->as<QV4::String>()) {
if (name == QStringLiteral("length"))
return QJSValue(string->d()->length());
@ -801,6 +807,11 @@ void QJSManagedValue::setProperty(const QString &name, const QJSValue &value)
if (!d)
return;
if (d->isNullOrUndefined()) {
v4Engine(d)->throwTypeError(
QStringLiteral("Value is null and could not be converted to an object"));
}
if (QV4::Object *obj = d->as<QV4::Object>()) {
QV4::ExecutionEngine *v4 = QJSValuePrivate::engine(&value);
if (Q_UNLIKELY(v4 && v4 != obj->engine())) {

View File

@ -1624,13 +1624,12 @@ void tst_QJSManagedValue::engineDeleted()
delete eng;
// You can still check the type, but anything involving the engine is obviously prohibited.
QCOMPARE(v1.type(), QJSManagedValue::Undefined);
QCOMPARE(v2.type(), QJSManagedValue::Undefined);
QCOMPARE(v3.type(), QJSManagedValue::Undefined);
QCOMPARE(v4.type(), QJSManagedValue::Undefined);
QCOMPARE(v5.type(), QJSManagedValue::Undefined);
QVERIFY(v3.property(QStringLiteral("foo")).isUndefined());
}
void tst_QJSManagedValue::valueOfWithClosure()
@ -1822,4 +1821,36 @@ void tst_QJSManagedValue::jsMetaTypes()
QVERIFY(halfPopulated.property("ccc").isUndefined());
}
void tst_QJSManagedValue::exceptionsOnNullAccess()
{
QJSEngine engine;
QJSManagedValue null(QJSValue(QJSValue::NullValue), &engine);
QJSManagedValue undef(QJSValue(QJSValue::UndefinedValue), &engine);
const QString nullReadError = engine.evaluate(
QStringLiteral("var n = null; n.prop")).toString();
const QString nullWriteError = engine.evaluate(
QStringLiteral("var n = null; n.prop = 5")).toString();
const QString undefReadError = engine.evaluate(
QStringLiteral("var n; n.prop")).toString();
const QString undefWriteError = engine.evaluate(
QStringLiteral("var n; n.prop = 5")).toString();
QVERIFY(null.property(QStringLiteral("prop")).isUndefined());
QVERIFY(engine.hasError());
QCOMPARE(engine.catchError().toString(), nullReadError);
null.setProperty(QStringLiteral("prop"), 5);
QVERIFY(engine.hasError());
QCOMPARE(engine.catchError().toString(), nullWriteError);
QVERIFY(undef.property(QStringLiteral("prop")).isUndefined());
QVERIFY(engine.hasError());
QCOMPARE(engine.catchError().toString(), undefReadError);
undef.setProperty(QStringLiteral("prop"), 5);
QVERIFY(engine.hasError());
QCOMPARE(engine.catchError().toString(), undefWriteError);
}
QTEST_MAIN(tst_QJSManagedValue)

View File

@ -110,6 +110,8 @@ private Q_SLOTS:
void stringByIndex();
void jsMetaTypes();
void exceptionsOnNullAccess();
private:
void newEngine() { engine.reset(new QJSEngine()); }
QScopedPointer<QJSEngine> engine;