diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 7aa0628168..f3a53dfccd 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -135,7 +135,7 @@ static int aggregateParameterCount(const QList &list) { int sum = 0; for (int i = 0; i < list.size(); ++i) - sum += list.at(i).arguments.size() + 1; // +1 for return type + sum += int(list.at(i).arguments.size()) + 1; // +1 for return type return sum; } @@ -293,7 +293,13 @@ void Generator::generateCode() fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0)); index += cdef->classInfoList.size() * 2; - const qsizetype methodCount = cdef->signalList.size() + cdef->slotList.size() + cdef->methodList.size(); + qsizetype methodCount = 0; + if (qAddOverflow(cdef->signalList.size(), cdef->slotList.size(), &methodCount) + || qAddOverflow(cdef->methodList.size(), methodCount, &methodCount)) { + parser->error("internal limit exceeded: the total number of member functions" + " (including signals and slots) is too big."); + } + fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0); index += methodCount * QMetaObjectPrivate::IntsPerMethod; if (cdef->revisionedMethods) @@ -305,7 +311,7 @@ void Generator::generateCode() + aggregateParameterCount(cdef->constructorList); index += totalParameterCount * 2 // types and parameter names - methodCount // return "parameters" don't have names - - cdef->constructorList.size(); // "this" parameters don't have names + - int(cdef->constructorList.size()); // "this" parameters don't have names fprintf(out, " %4d, %4d, // properties\n", int(cdef->propertyList.size()), int(cdef->propertyList.size() ? index : 0)); index += cdef->propertyList.size() * QMetaObjectPrivate::IntsPerProperty; @@ -333,8 +339,14 @@ void Generator::generateCode() // generateClassInfos(); + qsizetype propEnumCount = 0; // all property metatypes + all enum metatypes + 1 for the type of the current class itself - int initialMetaTypeOffset = cdef->propertyList.size() + cdef->enumList.size() + 1; + if (qAddOverflow(cdef->propertyList.size(), cdef->enumList.size(), &propEnumCount) + || qAddOverflow(propEnumCount, qsizetype(1), &propEnumCount) + || propEnumCount >= std::numeric_limits::max()) { + parser->error("internal limit exceeded: number of property and enum metatypes is too big."); + } + int initialMetaTypeOffset = int(propEnumCount); // // Build signals array first, otherwise the signal indices would be wrong @@ -606,7 +618,7 @@ void Generator::generateCode() // // Generate internal signal functions // - for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex) + for (int signalindex = 0; signalindex < int(cdef->signalList.size()); ++signalindex) generateSignal(&cdef->signalList[signalindex], signalindex); // @@ -712,7 +724,7 @@ void Generator::generateFunctions(const QList &list, const char *fu comment.append(" | MethodIsConst "); } - int argc = f.arguments.size(); + const int argc = int(f.arguments.size()); fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n", stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, initialMetatypeOffset, comment.constData()); @@ -963,7 +975,7 @@ void Generator::generateMetacall() QMultiMap Generator::automaticPropertyMetaTypesHelper() { QMultiMap automaticPropertyMetaTypes; - for (int i = 0; i < cdef->propertyList.size(); ++i) { + for (int i = 0; i < int(cdef->propertyList.size()); ++i) { const QByteArray propertyType = cdef->propertyList.at(i).type; if (registerableMetaType(propertyType) && !isBuiltinType(propertyType)) automaticPropertyMetaTypes.insert(propertyType, i); @@ -1012,7 +1024,7 @@ void Generator::generateStaticMetacall() if (!cdef->constructorList.isEmpty()) { fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n"); fprintf(out, " switch (_id) {\n"); - const int ctorend = cdef->constructorList.size(); + const int ctorend = int(cdef->constructorList.size()); for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) { fprintf(out, " case %d: { %s *_r = new %s(", ctorindex, cdef->classname.constData(), cdef->classname.constData()); @@ -1136,7 +1148,7 @@ void Generator::generateStaticMetacall() fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n"); fprintf(out, " int *result = reinterpret_cast(_a[0]);\n"); bool anythingUsed = false; - for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) { + for (int methodindex = 0; methodindex < int(cdef->signalList.size()); ++methodindex) { const FunctionDef &f = cdef->signalList.at(methodindex); if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic) continue; @@ -1234,7 +1246,7 @@ void Generator::generateStaticMetacall() if (needTempVarForGet) fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); if (p.read.isEmpty() && p.member.isEmpty()) continue; @@ -1275,7 +1287,7 @@ void Generator::generateStaticMetacall() setupMemberAccess(); fprintf(out, " void *_v = _a[0];\n"); fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); if (p.constant) continue; @@ -1328,7 +1340,7 @@ void Generator::generateStaticMetacall() if (needReset) { setupMemberAccess(); fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); if (p.reset.isEmpty()) continue; @@ -1349,7 +1361,7 @@ void Generator::generateStaticMetacall() if (hasBindableProperties) { setupMemberAccess(); fprintf(out, " switch (_id) {\n"); - for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) { + for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) { const PropertyDef &p = cdef->propertyList.at(propindex); if (p.bind.isEmpty()) continue; diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index f8c36a5abd..39fc5ca466 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -318,6 +318,9 @@ void Moc::parseFunctionArguments(FunctionDef *def) def->arguments.removeLast(); def->isRawSlot = true; } + + if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits::max())) + error("number of function arguments exceeds std::numeric_limits::max()"); } bool Moc::testFunctionAttribute(FunctionDef *def) @@ -603,6 +606,42 @@ void Moc::prependNamespaces(BaseDef &def, const QList &namespaceLi } } +void Moc::checkListSizes(const ClassDef &def) +{ + if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits::max())) + error("number of signals defined in parent class(es) exceeds " + "std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits::max())) + error("number of bindable properties exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits::max())) + error("number of times Q_CLASSINFO macro is used exceeds " + "std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits::max())) + error("number of enumerations exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits::max())) + error("number of super classes exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits::max())) + error("number of constructor parameters exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits::max())) + error("number of signals exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits::max())) + error("number of declared slots exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits::max())) + error("number of methods exceeds std::numeric_limits::max()."); + + if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits::max())) + error("number of public functions declared in this class exceeds " + "std::numeric_limits::max()."); +} + void Moc::parse() { QList namespaceList; @@ -974,6 +1013,8 @@ void Moc::parse() checkProperties(&def); + checkListSizes(def); + classList += def; QHash &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets; classHash.insert(def.classname, def.qualified); @@ -993,8 +1034,10 @@ void Moc::parse() if (it != classList.end()) { it->classInfoList += def.classInfoList; + Q_ASSERT(it->classInfoList.size() <= std::numeric_limits::max()); it->enumDeclarations.insert(def.enumDeclarations); it->enumList += def.enumList; + Q_ASSERT(it->enumList.size() <= std::numeric_limits::max()); it->flagAliases.insert(def.flagAliases); } else { knownGadgets.insert(def.classname, def.qualified); @@ -1915,7 +1958,7 @@ void Moc::checkProperties(ClassDef *cdef) } if (!p.notify.isEmpty()) { int notifyId = -1; - for (int j = 0; j < cdef->signalList.size(); ++j) { + for (int j = 0; j < int(cdef->signalList.size()); ++j) { const FunctionDef &f = cdef->signalList.at(j); if (f.name != p.notify) { continue; @@ -1926,10 +1969,10 @@ void Moc::checkProperties(ClassDef *cdef) } p.notifyId = notifyId; if (notifyId == -1) { - int index = cdef->nonClassSignalList.indexOf(p.notify); + const int index = int(cdef->nonClassSignalList.indexOf(p.notify)); if (index == -1) { cdef->nonClassSignalList << p.notify; - p.notifyId = -1 - cdef->nonClassSignalList.size(); + p.notifyId = int(-1 - cdef->nonClassSignalList.size()); } else { p.notifyId = -2 - index; } diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 512428356e..640e19e234 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -280,6 +280,8 @@ public: void checkSuperClasses(ClassDef *def); void checkProperties(ClassDef* cdef); + + void checkListSizes(const ClassDef &def); }; inline QByteArray noRef(const QByteArray &type)