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

QSA-interest Archive, February 2006
QSA 1.2.0: Assert failure w/ large Enum values


Message 1 in thread

Hey all,

I think I found another bug with QSA 1.2.0.  I haven't spend much  
time yet trying to see if there's an easy fix.

Here is the bug: if an object has an enum with a large (larger than  
2<<16) value, trying to access than enum causes QSA to abort on an  
assert failure.  For example,

For example, consider this class:

class TestClass: public QObject {
	Q_OBJECT
	Q_ENUMS(Crash);

public:
	TestClass();
	virtual ~TestClass();

	enum Crash { BadValue = 0x02000000 };
};

If there is an instance of that class in the script environment, and  
the script tries to use the "BadValue" enum value, QSA aborts with  
this error:

ASSERT: "member_index < (2<<16)" in file ../kernel/quickobjects.cpp,  
line 88

It seems that QSA checks the enum value (0x02000000 in this case),  
and if it is bigger than a 16-bit value (as this one is), it fails  
this assertion.

For now, I will rewrite my code to use smaller enum values, but it  
would be nice if this wasn't necessary.  (For flag-type enums where  
each value sets a different bit, it is quite easy to have values  
larger than 16-bit.)

Regards,
Joel Nordell
Software Engineer
ONEAC Corp.



Message 2 in thread

Joel Nordell wrote:
> Hey all,
> 
> I think I found another bug with QSA 1.2.0.  I haven't spend much  time 
> yet trying to see if there's an easy fix.
> 
> Here is the bug: if an object has an enum with a large (larger than  
> 2<<16) value, trying to access than enum causes QSA to abort on an  
> assert failure.  For example,

Hi Joel,

This is a bug, and the attahed patch should fix the problem.

-
Gunnar
==== src/kernel/quickobjects.cpp - src\kernel\quickobjects.cpp ====
==== src/kernel/quickobjects.cpp - src\kernel\quickobjects.cpp ====
@@ -53,28 +53,39 @@
 
 using namespace QS;
 
-// static QSObject uObjectToQS(QuickInterpreter *ip,
-// 			     QUObject *o, const void *extra=0);
-// static bool qsToUObject( QUObject *o,
-// 			  const QSObject &v,
-// 			  QUType *t,
-// 			  const void *extra,
-// 			  Q3PtrList<qs_ptr_ref> *allocs,
-//                           qs_method_info *);
+// Returns a uint that has the \a x lowest bit set.
+static inline uint low_bits(int x) {
+    return 0xffffffff >> (32 - x);
+}
+
+const int OBJECT_INDEX_SIZE = 5;
+const int MEMBER_TYPE_SIZE = 3;
+const int MEMBER_INDEX_SIZE = 24;
 
 static inline uint  qsa_encode_member_index(QSWrapperClass::MemberType member_type, uint object_index, uint member_index)
 {
     // make sure we have enough space...
-    Q_ASSERT(object_index < 256);
-    Q_ASSERT(member_type < 256);
-    Q_ASSERT(member_index < (2<<16));
+    Q_ASSERT(object_index < (1<<OBJECT_INDEX_SIZE));
+    Q_ASSERT(member_type < (1<<MEMBER_TYPE_SIZE));
+    Q_ASSERT(member_index < (1<<MEMBER_INDEX_SIZE));
+
+    return (object_index << (32 - OBJECT_INDEX_SIZE))
+        | (member_type << (32 - MEMBER_TYPE_SIZE - OBJECT_INDEX_SIZE))
+        | member_index;
+}
+
+static inline uint qsa_decode_index_object(uint index) {
+    return index >> (32 - OBJECT_INDEX_SIZE);
+}
+
+static inline uint qsa_decode_index_type(uint index) {
+    return (index >> (32 - OBJECT_INDEX_SIZE - MEMBER_TYPE_SIZE)) & low_bits(MEMBER_TYPE_SIZE);
+}
 
-    return (object_index << 24) | (member_type << 16) | member_index;
+static inline uint qsa_decode_index_member(uint index) {
+    return index & low_bits(MEMBER_INDEX_SIZE);
 }
 
-static inline uint qsa_decode_index_object(uint index) { return index >> 24; }
-static inline uint qsa_decode_index_type(uint index) { return (index >> 16) & 0xff; }
-static inline uint qsa_decode_index_member(uint index) { return index & 0x0000ffff; }
 
 QSObject qsa_execute_slot(QSEnv *env, QObject *qobject, const QList<int> &slot_indexes);
 
@@ -282,7 +293,7 @@
 
         // enums
         {
-            int value = -1;
+            uint value = 0;
             bool ok = false;
             for (int search_idx = meta_object->enumeratorCount() - 1;
                  search_idx >= 0 && !ok;
@@ -291,7 +302,7 @@
                 for (int key_idx=0; key_idx<metaEnum.keyCount() && !ok; ++key_idx) {
                     if (qstrcmp(metaEnum.key(key_idx), member_name) == 0) {
                         ok = true;
-                        value = metaEnum.value(key_idx);
+                        value = (key_idx & low_bits(14)) | ((search_idx & low_bits(10)) << 14);
                     }
                 }
             }
@@ -343,7 +354,13 @@
         break;
 
     case EnumType:
-        return env()->createNumber(member_index);
+        {
+            int search_idx = (member_index >> 14) & low_bits(10);
+            int key_idx = (member_index & low_bits(14));
+
+            QMetaEnum metaEnum = meta_object->enumerator(search_idx);
+            return env()->createNumber(metaEnum.value(key_idx));
+        }
         break;
 
     case ObjectType: