From 810a0afe1e9bd14e4393a73bf6c299b25745dbc5 Mon Sep 17 00:00:00 2001
From: Richard Weickelt <richard@weickelt.de>
Date: Tue, 24 Nov 2020 01:14:28 +0100
Subject: [PATCH 13/28] Fix crash when calling hasOwnProperty() on proxy object

Property pointer p needs to be checked for nullptr value in
QV4::ProxyObject::virtualGetOwnProperty(). This can happen when calling
hasOwnProperty() or propertyIsEnumerable().

Fixes: QTBUG-88786
Change-Id: I43da58fed4d8656f9187213f7317f17398739e34
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit 9b321a34490cd17c0eb043b69bd7c9d8d8f513d5)
Reviewed-by: Richard Weickelt <richard@weickelt.de>
---
 src/qml/jsruntime/qv4proxy.cpp                | 10 +++---
 .../qml/qqmlecmascript/tst_qqmlecmascript.cpp | 31 ++++++++++++++++++-
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 24676ffd00..1505eae426 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -265,9 +265,9 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
     ScopedProperty targetDesc(scope);
     PropertyAttributes targetAttributes = target->getOwnProperty(id, targetDesc);
     if (trapResult->isUndefined()) {
-        p->value = Encode::undefined();
-        if (targetAttributes == Attr_Invalid) {
+        if (p)
             p->value = Encode::undefined();
+        if (targetAttributes == Attr_Invalid) {
             return Attr_Invalid;
         }
         if (!targetAttributes.isConfigurable() || !target->isExtensible()) {
@@ -295,8 +295,10 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
         }
     }
 
-    p->value = resultDesc->value;
-    p->set = resultDesc->set;
+    if (p) {
+        p->value = resultDesc->value;
+        p->set = resultDesc->set;
+    }
     return resultAttributes;
 }
 
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 1e10841430..3a9d1bfb4c 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -382,7 +382,7 @@ private slots:
     void semicolonAfterProperty();
     void hugeStack();
     void variantConversionMethod();
-
+    void proxyHandlerTraps();
     void gcCrashRegressionTest();
 
 private:
@@ -9306,6 +9306,35 @@ void tst_qqmlecmascript::variantConversionMethod()
     QCOMPARE(obj.funcCalled, QLatin1String("QModelIndex"));
 }
 
+void tst_qqmlecmascript::proxyHandlerTraps()
+{
+    const QString expression = QStringLiteral(R"SNIPPET(
+        (function(){
+            const target = {
+                prop: 47
+            };
+            const handler = {
+                getOwnPropertyDescriptor(target, prop) {
+                    return { configurable: true, enumerable: true, value: 47 };
+                }
+            };
+            const proxy = new Proxy(target, handler);
+
+            // QTBUG-88786
+            if (!proxy.propertyIsEnumerable("prop"))
+                throw Error("FAIL: propertyisEnumerable");
+            if (!proxy.hasOwnProperty("prop"))
+                throw Error("FAIL: hasOwnProperty");
+
+            return "SUCCESS";
+        })()
+    )SNIPPET");
+
+    QJSEngine engine;
+    QJSValue value = engine.evaluate(expression);
+    QVERIFY(value.isString() && value.toString() == QStringLiteral("SUCCESS"));
+}
+
 QTEST_MAIN(tst_qqmlecmascript)
 
 #include "tst_qqmlecmascript.moc"
-- 
2.31.1

