Moc: check sizes of specific member QLists are within INT_MAX range

Parts of the public API, e.g. QMetaMethod::methodIndex and similar
functions return int, and other parts of the code expect int values, at
least for Qt6 this can't be changed, so use qsizetype internally and
assert the values fit in an int.

As pointed out in code review, not many people will build moc in debug
mode, so asserts aren't that useful here. Instead print error messages
and exit, like is already done in other parts of the code.

Change-Id: Id305165caa996c899f30770a757098fe2f9a96f6
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Ahmad Samir 2023-05-25 19:22:05 +03:00
parent 2cca2323d3
commit 88de696074
3 changed files with 73 additions and 16 deletions

View File

@ -135,7 +135,7 @@ static int aggregateParameterCount(const QList<FunctionDef> &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<int>::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<FunctionDef> &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<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
{
QMultiMap<QByteArray, int> 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<int *>(_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;

View File

@ -318,6 +318,9 @@ void Moc::parseFunctionArguments(FunctionDef *def)
def->arguments.removeLast();
def->isRawSlot = true;
}
if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<int>::max()))
error("number of function arguments exceeds std::numeric_limits<int>::max()");
}
bool Moc::testFunctionAttribute(FunctionDef *def)
@ -603,6 +606,42 @@ void Moc::prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceLi
}
}
void Moc::checkListSizes(const ClassDef &def)
{
if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<int>::max()))
error("number of signals defined in parent class(es) exceeds "
"std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<int>::max()))
error("number of bindable properties exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<int>::max()))
error("number of times Q_CLASSINFO macro is used exceeds "
"std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<int>::max()))
error("number of enumerations exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<int>::max()))
error("number of super classes exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<int>::max()))
error("number of constructor parameters exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<int>::max()))
error("number of signals exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<int>::max()))
error("number of declared slots exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<int>::max()))
error("number of methods exceeds std::numeric_limits<int>::max().");
if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<int>::max()))
error("number of public functions declared in this class exceeds "
"std::numeric_limits<int>::max().");
}
void Moc::parse()
{
QList<NamespaceDef> namespaceList;
@ -974,6 +1013,8 @@ void Moc::parse()
checkProperties(&def);
checkListSizes(def);
classList += def;
QHash<QByteArray, QByteArray> &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<int>::max());
it->enumDeclarations.insert(def.enumDeclarations);
it->enumList += def.enumList;
Q_ASSERT(it->enumList.size() <= std::numeric_limits<int>::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;
}

View File

@ -280,6 +280,8 @@ public:
void checkSuperClasses(ClassDef *def);
void checkProperties(ClassDef* cdef);
void checkListSizes(const ClassDef &def);
};
inline QByteArray noRef(const QByteArray &type)