Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-88786

Crash when calling hasOwnProperty() on a JS Proxy Object

    XMLWordPrintable

    Details

    • Commits:
      9b321a34490cd17c0eb043b69bd7c9d8d8f513d5 (qt/qtdeclarative/dev) b3848de6945d8514b6bea0909659310cbe38af61 (qt/qtdeclarative/6.0) 810a0afe1e9bd14e4393a73bf6c299b25745dbc5 (qt/qtdeclarative/5.15)

      Description

      Calling hasOwnProperty() on a proxy object correctly invokes the getOwnPropertyDescriptor() trap. But the program crashes because QV4::ProxyObject::virtualGetOwnProperty() tries to assign data to a null-pointer at https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/qml/jsruntime/qv4proxy.cpp?h=5.15.2#n268

      Example:

      #include <QtCore/qcoreapplication.h>
      #include <QtCore/qdebug.h>
      #include <QtCore/qobject.h>
      #include <QtCore/qtimer.h>
      #include <QtCore/qstring.h>
      #include <QtQml/qjsengine.h>
      #include <QtQml/qjsvalue.h>
      
      static const QString jsCode = QStringLiteral(R"666(
           (function(handler){
              const target = {};
              const proxy = new Proxy(target, handler);
              if (proxy.hasOwnProperty("does_not_exist")) { // crashes
                  console.log("FAIL");
              } else {
                  console.log("SUCCESS");
              }
           })
      )666");
      
      class ProxyHandler: public QObject {
          Q_OBJECT
      public:
          // This is a non-sense handler, but should be valid.
          Q_INVOKABLE QJSValue getOwnPropertyDescriptor(QJSValue target, const QJSValue &key)
          {
              Q_ASSERT(key.isString());
      
              QJSValue result;
              QString name = key.toString();
              if (target.hasOwnProperty(name)) {
                  QJSValue value = target.property(name);
                  result = qjsEngine(this)->newObject();
                  result.setProperty(QStringLiteral("configurable"), true);
                  result.setProperty(QStringLiteral("enumerable"), true);
                  result.setProperty(QStringLiteral("writable"), false);
                  result.setProperty(QStringLiteral("value"), value);
              }
              return result;
          }
      };
      
      void test() {
          QJSEngine engine;
          engine.installExtensions(QJSEngine::ConsoleExtension);
          QJSValue proxyTest = engine.evaluate(jsCode, QStringLiteral("proxy.js"));
          if (proxyTest.isError())
              qWarning() << "Error: " << proxyTest.toString();
          Q_ASSERT(!proxyTest.isError());
      
          QJSValue handler = engine.newQObject(new ProxyHandler());
          QJSValue result = proxyTest.call(QJSValueList{ handler });
          if (result.isError())
              qWarning() << "Error: " << result.toString();
          Q_ASSERT(!result.isError());
      
          QCoreApplication::exit(0);
      }
      
      int main(int argc, char *argv[])
      {
          QCoreApplication app(argc, argv);
          QTimer::singleShot(0, &test);
          return app.exec();
      }
      
      #include "main.moc"
      

      The Object.isEnumerableProperty() is affected, too.

        Attachments

          Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            Activity

              People

              Assignee:
              qt.team.quick.subscriptions Qt Quick and Widgets Team
              Reporter:
              rweickelt Richard Weickelt
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:

                  Gerrit Reviews

                  There are no open Gerrit changes