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

QScriptClass-implemented constructors lead to application crash (patch suggested)

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: P2: Important P2: Important
    • 4.6.3
    • 4.6.1
    • Qt Script
    • None
    • Linux-x86_64RHEL5
      gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
    • 04d4cbeb36f75661aca06f93066a8603afd96f76

      Implementing the Callable extension in a QScriptClass allows scripts to call objects as either functions or constructors. When called as a constructor (i.e. with the "new" keyword), this leads to an application crash after several more lines of script code are executed. For instance:

      var a = new A(); // where object "A" has a custom QScriptClass that implements the constructor.
      print( "1" );
      print( "2" ); // this line crashes.

      There is no problem if you implement A's Callable extension to work as a constructor even when not called as a constructor:

      var a2 = A(); // this constructor does not cause a crash later on.

      The attached code demonstrates this bug. when running the three-line script given above.

      Looking at the Qt source code, this bug appears to be due to incorrect handling of the scripting call stack in ClassObjectDelege::construct() (in src/script/bridge/qscriptclassobject.cpp), which pushes context, but never pops it back off after the QScriptClass::extension() call. Here's is a patched version which causes the attached example to work correctly:

      JSC::JSObject* ClassObjectDelegate::construct(JSC::ExecState *exec, JSC::JSObject *callee,
      const JSC::ArgList &args)
      {
      Q_ASSERT(callee->inherits(&QScriptObject::info));
      QScriptObject obj = static_cast<QScriptObject>(callee);
      QScriptObjectDelegate *delegate = obj->delegate();
      QScriptClass scriptClass = static_cast<ClassObjectDelegate>(delegate)->scriptClass();

      QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);

      // =============================================================
      // Change #1 begins here. This line is commented out in 4.6.1 source code
      // =============================================================
      JSC::ExecState *oldFrame = eng_p->currentFrame;
      // =============================================================
      // End change 1
      // =============================================================
      eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
      QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);

      QScriptValue defaultObject = ctx->thisObject();
      QScriptValue result = qvariant_cast<QScriptValue>(scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx)));

      // =============================================================
      // Begin change 2: pop context and restore the frame pointer.
      // =============================================================
      eng_p->popContext();
      eng_p->currentFrame = oldFrame;
      // =============================================================
      // End change 2
      // =============================================================

      if (!result.isObject())
      result = defaultObject;
      return JSC::asObject(eng_p->scriptValueToJSCValue(result));
      }

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

            kenthans Kent Hansen (Inactive)
            daniel.baker@remcom.com Daniel Baker
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes