uic: Relax property name checks

Use an approximation of the "Unicode Standard Annex #31"
for checking the property names and enumerations.

Remove check for dynamic properties and use character literal
formatting for them instead, which will escape offending characters.

As a drive-by, use QStringView parameters for the check function.

Amends 53c8d1fe7c59f3462b85193b688d02ff353b51d5.

Task-number: QTBUG-126265
Task-number: QTBUG-126860
Pick-to: 6.7 6.5 6.2 5.15
Change-Id: I90fe555e64327e4164a17c1af0a734e4b1d834db
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
(cherry picked from commit aae20da52a11e0ebb8c4f5fcfb95ce6744f659a3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Friedemann Kleint 2024-06-14 07:40:09 +02:00 committed by Qt Cherry-pick Bot
parent bc28d6d48c
commit 0925c2d80a

View File

@ -125,35 +125,65 @@ namespace {
return iconHasStatePixmaps(i) || !i->attributeTheme().isEmpty(); return iconHasStatePixmaps(i) || !i->attributeTheme().isEmpty();
} }
// Checks on property names // An approximation of "Unicode Standard Annex #31" for checking property
bool isIdentifier(QChar c) { return c.isLetterOrNumber() || c == u'_'; } // and enumeration identifiers to prevent code injection attacks.
// FIXME 6.9: Simplify according to QTBUG-126860
bool checkPropertyName(const QString &name) static bool isIdStart(QChar c)
{ {
return !name.isEmpty() && name.at(0).isLetter() bool result = false;
&& std::all_of(name.cbegin(), name.cend(), isIdentifier); switch (c.category()) {
case QChar::Letter_Uppercase:
case QChar::Letter_Lowercase:
case QChar::Letter_Titlecase:
case QChar::Letter_Modifier:
case QChar::Letter_Other:
case QChar::Number_Letter:
result = true;
break;
default:
result = c == u'_';
break;
}
return result;
} }
// Basic checks on enum/flag values static bool isIdContinuation(QChar c)
static bool isValidEnumValue(QChar c)
{ {
if (c.isLetterOrNumber()) bool result = false;
return true; switch (c.category()) {
switch (c.unicode()) { case QChar::Letter_Uppercase:
case '|': case QChar::Letter_Lowercase:
case ' ': case QChar::Letter_Titlecase:
case ':': case QChar::Letter_Modifier:
case '_': case QChar::Letter_Other:
return true; case QChar::Number_Letter:
case QChar::Mark_NonSpacing:
case QChar::Mark_SpacingCombining:
case QChar::Number_DecimalDigit:
case QChar::Punctuation_Connector: // '_'
result = true;
break;
default: default:
break; break;
} }
return false; return result;
} }
bool checkEnumValue(const QString &value) static bool isEnumIdContinuation(QChar c)
{ {
return std::all_of(value.cbegin(), value.cend(), isValidEnumValue); return c == u':' || c == u'|' || c == u' ' || isIdContinuation(c);
}
bool checkPropertyName(QStringView name)
{
return !name.isEmpty() && isIdStart(name.at(0))
&& std::all_of(name.cbegin() + 1, name.cend(), isIdContinuation);
}
bool checkEnumValue(QStringView name)
{
return !name.isEmpty() && isIdStart(name.at(0))
&& std::all_of(name.cbegin() + 1, name.cend(), isEnumIdContinuation);
} }
QString msgInvalidValue(const QString &name, const QString &value) QString msgInvalidValue(const QString &name, const QString &value)
@ -169,7 +199,8 @@ namespace {
const DomProperty *p) { const DomProperty *p) {
const QString &name = p->attributeName(); const QString &name = p->attributeName();
if (!checkPropertyName(name)) { const bool isDynamicProperty = p->hasAttributeStdset() && p->attributeStdset() == 0;
if (!isDynamicProperty && !checkPropertyName(name)) {
qWarning("uic: Invalid property name: \"%s\".", qPrintable(name)); qWarning("uic: Invalid property name: \"%s\".", qPrintable(name));
return false; return false;
} }
@ -1403,8 +1434,8 @@ void WriteInitialization::writeProperties(const QString &varName,
str << language::derefPointer <<"set" << propertyName.at(0).toUpper() str << language::derefPointer <<"set" << propertyName.at(0).toUpper()
<< QStringView{propertyName}.mid(1) << '('; << QStringView{propertyName}.mid(1) << '(';
} else { } else {
str << language::derefPointer << "setProperty(\""_L1 str << language::derefPointer << "setProperty("_L1
<< propertyName << "\", "; << language::charliteral(propertyName) << ", ";
if (language::language() == Language::Cpp) { if (language::language() == Language::Cpp) {
str << "QVariant"; str << "QVariant";
if (p->kind() == DomProperty::Enum) if (p->kind() == DomProperty::Enum)