Trolltech Home | QSA-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

QSA-interest Archive, February 2006
Re: QSA crash when calling a slot that returns QVariant


Message 1 in thread

Hi
Thanks for the fix... that helped me a lot.

But QSA still crashes if a function returns an invalid QVariant like this:

	return QVariant();

I wanted to use this if the slot-function did not succeed.
Right now I have to work around this problem this way:
	
	return QVariant( QString("") );

Will this be fixed in QSA 1.2.1, too?

	Greetings
		Jens

Am Freitag, 20. Januar 2006 03:09 schrieb Joel Nordell:
> Hello,
>
> I believe I have found a bug in QSA 1.2.0 w/ Qt 4.1.0.  I'm porting a
> large project from Qt 3 to Qt 4, and really giving QSA a good
> workout!  :)
>
> QSA seems to crash whenever a script calls a slot that returns a
> QVariant.  I've attached an example program that illustrates this.
>
> I have also figured out a potential fix.  In the file src/kernel/
> quickobjects.cpp, change the qsa_default_value function to this:
>
> ---
> static void *qsa_default_value(QSASlotCaching *caching, const
> QSATypeInfo &ti)
> {
>      const QVariant *v = caching->variants(QVariant::Type(ti.id));
>      void *const_data = (void *) v->constData();
>
>      if (v->type() == QVariant::Invalid) {
>          if (ti.name == "QList<int>")
>              return caching->intlists(QList<int>());
>          else if (ti.name == "QObjectList")
>              return caching->qobjectlists(QObjectList());
>          else if (ti.name == "QVariant")  // <--- These two lines fix
> the crash
>              return caching->variants(QVariant());
>          else if (ti.name.count('*') == 0 && ti.name.length() > 0)
>              return 0;
>      }
>
>      return const_data;
> }
> ---
>
> Note the added condition to checki if ti.name == "QVariant".  That
> seems to do the trick.
>
> Joel Nordell
> Software Engineer
> ONEAC Corp.
>
> ïï

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 2 in thread

Hi Jens,

Here is my patch to fix the crash on return of an invalid QVariant--

In src/kernel/quickobjects.cpp, in the convert_qt2qsa function,  
change this:

     } else if (ti.name == "QVariant") {
         // We could have casted directly, but we choose to use
         // the common code path
         QVariant *var = ((QVariant *) value);
         return qsa_script_variant(ip, var->type(), (void *) var- 
 >constData());

to this:

     } else if (ti.name == "QVariant") {
         // We could have casted directly, but we choose to use
         // the common code path
         QVariant *var = ((QVariant *) value);
         if (var->isNull()) return env->createUndefined();
         else return qsa_script_variant(ip, var->type(), (void *) var- 
 >constData());

I've been sending these patches to Gunnar at TrollTech, so hopefully  
they will be included in QSA 1.2.1.

-Joel


On Feb 7, 2006, at 7:40 AM, Jens G. wrote:

> Hi
> Thanks for the fix... that helped me a lot.
>
> But QSA still crashes if a function returns an invalid QVariant  
> like this:
>
> 	return QVariant();
>
> I wanted to use this if the slot-function did not succeed.
> Right now I have to work around this problem this way:
> 	
> 	return QVariant( QString("") );
>
> Will this be fixed in QSA 1.2.1, too?
>
> 	Greetings
> 		Jens
>
> Am Freitag, 20. Januar 2006 03:09 schrieb Joel Nordell:
>> Hello,
>>
>> I believe I have found a bug in QSA 1.2.0 w/ Qt 4.1.0.  I'm porting a
>> large project from Qt 3 to Qt 4, and really giving QSA a good
>> workout!  :)
>>
>> QSA seems to crash whenever a script calls a slot that returns a
>> QVariant.  I've attached an example program that illustrates this.
>>
>> I have also figured out a potential fix.  In the file src/kernel/
>> quickobjects.cpp, change the qsa_default_value function to this:
>>
>> ---
>> static void *qsa_default_value(QSASlotCaching *caching, const
>> QSATypeInfo &ti)
>> {
>>      const QVariant *v = caching->variants(QVariant::Type(ti.id));
>>      void *const_data = (void *) v->constData();
>>
>>      if (v->type() == QVariant::Invalid) {
>>          if (ti.name == "QList<int>")
>>              return caching->intlists(QList<int>());
>>          else if (ti.name == "QObjectList")
>>              return caching->qobjectlists(QObjectList());
>>          else if (ti.name == "QVariant")  // <--- These two lines fix
>> the crash
>>              return caching->variants(QVariant());
>>          else if (ti.name.count('*') == 0 && ti.name.length() > 0)
>>              return 0;
>>      }
>>
>>      return const_data;
>> }
>> ---
>>
>> Note the added condition to checki if ti.name == "QVariant".  That
>> seems to do the trick.
>>
>> Joel Nordell
>> Software Engineer
>> ONEAC Corp.
>>
>
> To unsubscribe - send "unsubscribe" in the subject to qsa-interest- 
> request@xxxxxxxxxxxxx

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 3 in thread

I am looking for a way to get notified when the interpreter has
finished running. I would assume there to be a signal "stopped" or
"terminated" in QSInterpreter, but unfortunately there isn't any.

So is the only way to poll isRunning() ?

Peter

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 4 in thread

Peter Koch wrote:
> I am looking for a way to get notified when the interpreter has
> finished running. I would assume there to be a signal "stopped" or
> "terminated" in QSInterpreter, but unfortunately there isn't any.
> 
> So is the only way to poll isRunning() ?

For normal execution you could trigger this yourself, since you call 
QSInterpterer::evaluate() and QSInterpreter::call(). In your class you 
could encapsulate those calls with:

emit interpreterStarted();
interpreter.evaluate(code);
emit interpreterStopped();

and similar for call(). This would give all execution, except when the 
interpreter is running a slot connection.

I can note this down as a suggestion for future versions though.

-
Best regards,
Gunnar

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 5 in thread

1. When an object is created in a QSObjectFactory, should I assign a
parent object to it, or will QSA do that and therefore care for
deleting the object when it is no longer needed?

2. When my object has a slot for creating subobjects (a factory-slot),
the same question: Should my object take care for deleting the
subobject, or is the creating object responsible for it?

EXAMPLE

-------------------------
Script:

function foo()
{
    var obj = new MyObject;
    {
        sub1 = obj.createSubObject();
        sub2 = new MyObject;
    }
    // will sub1 / sub2 have been deleted here by interpreter?
}
// will obj / sub1 / sub2 have been deleted here by interpreter?

----------------------------
C++ Class:

class MyObject : public QObject
{
    Q_OBJECT
    
public:
    MyObject(QObject *parent) : QObject(parent)
    {
        setObjectName("MyObject");
    }

public slots:
    MyObject* createSubObject()
    {
        return new MyObject(this);
    }
};
-----------------------------
Factory:

QObject* MyObjectFactory::create(
    const QString& name, const QVariantLoist& args, QObject* context)
{
    if (name == "MyObject")
        return new MyObject(/* what parent here: 0, context or this? */);
    return 0;
}

I hope somebody can shed a light on this.

Thanks,
Peter

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 6 in thread

Here are the results as far as I figured out with the test below.
Somebody may correct me if my interpretation is wrong:

1. Objects created by a "factory slot" stay in the ownership of the
creating class.

2. Opjects created with a QSObjectFactory (new ... in the script) are
owned by the interpreter who will care for deleting them.

Here is my test with the results:

--------------------------------8<--------------------------------
main.h:

#ifndef MAIN_H
#define MAIN_H
#include <qsinterpreter.h>
#include <qsobjectfactory.h>

class MyClass : public QObject
{
        Q_OBJECT
        Q_PROPERTY(QString name WRITE setName READ name)
public:
        MyClass(QObject* parent = 0) : QObject(parent) { setObjectName("MyClass"); } 
        ~MyClass() { qDebug(QString("destruct %1").arg(m_name).toAscii()); }
public slots:
        QString name() const { return m_name; }
        void setName(const QString& name) { m_name = name; }
        MyClass* create() { return new MyClass(this); }
private:
        QString m_name;
};

class Factory : public QSObjectFactory
{
public:
        Factory() {     registerClass("MyClass", &MyClass::staticMetaObject); }
        QObject* create(const QString& name, const QVariantList& arguments, QObject *context)
        {
                if (name == "MyClass") return new MyClass(context);
                throwError("Class "+name+" not implemented.");
                return 0;
        }
};
#endif

--------------------------------8<--------------------------------
main.c:

#include <QtCore/QCoreApplication>
#include "main.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
        QSInterpreter qsi;
        qsi.addObjectFactory(new Factory);
        qsi.evaluate(
                "function foo()\n"
                "{\n"
                "  debug('begin foo');\n"
                "  var obj = new MyClass;\n"
                "  obj.name = 'obj';\n"
                "  for (var i = 0; i < 3; i++) {\n"
                "    debug('begin block '+i);\n"
                "    var sub1 = new MyClass;\n"
                "    sub1.name = 'sub1-'+i;\n"
                "    var sub2 = obj.create();\n"
                "    sub2.name = 'sub2-'+i;\n"
                "    debug('end block '+i);\n"
                "  }"
                "  debug('end foo');\n"
                "}\n"
                "\n"
                "debug('call foo');\n"
                "foo();\n"
                "debug('returned from foo');\n"
        );
        qDebug("evaluate finished");
}

--------------------------------8<--------------------------------
output:

---> call foo
---> begin foo
---> begin block 0
---> end block 0
---> begin block 1
destruct sub1-0
---> end block 1
---> begin block 2
destruct sub1-1
---> end block 2
---> end foo
destruct sub1-2
destruct obj
destruct sub2-0
destruct sub2-1
destruct sub2-2
---> returned from foo
evaluate finished
--------------------------------8<--------------------------------

Peter





> 1. When an object is created in a QSObjectFactory, should I assign a
> parent object to it, or will QSA do that and therefore care for
> deleting the object when it is no longer needed?

> 2. When my object has a slot for creating subobjects (a factory-slot),
> the same question: Should my object take care for deleting the
> subobject, or is the creating object responsible for it?

> EXAMPLE

> -------------------------
> Script:

> function foo()
> {
>     var obj = new MyObject;
>     {
>         sub1 = obj.createSubObject();
>         sub2 = new MyObject;
>     }
>     // will sub1 / sub2 have been deleted here by interpreter?
> }
> // will obj / sub1 / sub2 have been deleted here by interpreter?

> ----------------------------
> C++ Class:

> class MyObject : public QObject
> {
>     Q_OBJECT
    
> public:
>     MyObject(QObject *parent) : QObject(parent)
>     {
>         setObjectName("MyObject");
>     }

> public slots:
>     MyObject* createSubObject()
>     {
>         return new MyObject(this);
>     }
> };
> -----------------------------
> Factory:

> QObject* MyObjectFactory::create(
>     const QString& name, const QVariantLoist& args, QObject* context)
> {
>     if (name == "MyObject")
>         return new MyObject(/* what parent here: 0, context or this? */);
>     return 0;
> }

> I hope somebody can shed a light on this.

> Thanks,
> Peter

> To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx


Message 7 in thread

Peter Koch wrote:
> Here are the results as far as I figured out with the test below.
> Somebody may correct me if my interpretation is wrong:
> 
> 1. Objects created by a "factory slot" stay in the ownership of the
> creating class.
> 
> 2. Opjects created with a QSObjectFactory (new ... in the script) are
> owned by the interpreter who will care for deleting them.

Unless the object has a parent at object shutdown time, in which case 
ownership is transferred to the parent automatically cleaned when the 
parent is cleaned.

-
Gunnar

To unsubscribe - send "unsubscribe" in the subject to qsa-interest-request@xxxxxxxxxxxxx