From 90df0f48062310e29494df3449fd68c12e6694b5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 13 Nov 2023 16:00:00 -0800 Subject: [PATCH] QFactoryLoader: rewrite parse() using the new iterateInPluginMetaData() This doesn't simplify the actual parsing or make it any faster, but does merge the validation code so we only have it in one place. Change-Id: I8bd6bb457b9c42218247fffd1797543bec9cfbec Reviewed-by: Thiago Macieira Reviewed-by: Eirik Aavitsland Reviewed-by: Edward Welbourne --- src/corelib/plugin/qfactoryloader.cpp | 56 +++++++++++++++++---------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index fce9f098b7..722fcce978 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -62,7 +62,8 @@ struct QFactoryLoaderIidSearch { QLatin1StringView iid; bool matchesIid = false; - QFactoryLoaderIidSearch(QLatin1StringView iid) : iid(iid) {} + QFactoryLoaderIidSearch(QLatin1StringView iid) : iid(iid) + { Q_ASSERT(!iid.isEmpty()); } static QString readString(QCborStreamReader &reader) { @@ -93,7 +94,7 @@ struct QFactoryLoaderIidSearch matchesIid = (readString(reader) == iid); return IterationResult::FinishedSearch; } - IterationResult::Result operator()(const QCborValue &, QCborStreamReader &reader) + IterationResult::Result operator()(const QString &, QCborStreamReader &reader) { return skip(reader); } @@ -129,11 +130,13 @@ template static IterationResult iterateInPluginMetaData(QByteArrayV if (!reader.next()) return reader.lastError(); r = f(key, reader); - } else { - QCborValue key = QCborValue::fromCbor(reader); - if (key.isInvalid()) + } else if (reader.isString()) { + QString key = readString(reader); + if (key.isNull()) return reader.lastError(); r = f(key, reader); + } else { + return IterationResult::InvalidTopLevelItem; } if (QCborError e = reader.lastError()) @@ -156,24 +159,35 @@ static bool isIidMatch(QByteArrayView raw, QLatin1StringView iid) bool QPluginParsedMetaData::parse(QByteArrayView raw) { - QPluginMetaData::Header header; - Q_ASSERT(raw.size() >= qsizetype(sizeof(header))); - memcpy(&header, raw.data(), sizeof(header)); - if (Q_UNLIKELY(header.version > QPluginMetaData::CurrentMetaDataVersion)) + QCborMap map; + auto r = iterateInPluginMetaData(raw, [&](const auto &key, QCborStreamReader &reader) { + QCborValue item = QCborValue::fromCbor(reader); + if (item.isInvalid()) + return IterationResult::ParsingError; + if constexpr (std::is_enum_v>) + map[int(key)] = item; + else + map[key] = item; + return IterationResult::ContinueSearch; + }); + + switch (r.result) { + case IterationResult::FinishedSearch: + case IterationResult::ContinueSearch: + break; + + // parse errors + case IterationResult::ParsingError: + return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(r.error.toString())); + case IterationResult::InvalidMetaDataVersion: return setError(QFactoryLoader::tr("Invalid metadata version")); - - // use fromRawData to keep QCborStreamReader from copying - raw = raw.sliced(sizeof(header)); - QByteArray ba = QByteArray::fromRawData(raw.data(), raw.size()); - QCborParserError err; - QCborValue metadata = QCborValue::fromCbor(ba, &err); - - if (err.error != QCborError::NoError) - return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(err.error.toString())); - if (!metadata.isMap()) + case IterationResult::InvalidTopLevelItem: + case IterationResult::InvalidHeaderItem: return setError(QFactoryLoader::tr("Unexpected metadata contents")); - QCborMap map = metadata.toMap(); - metadata = {}; + } + + // header was validated + auto header = qFromUnaligned(raw.data()); DecodedArchRequirements archReq = header.version == 0 ? decodeVersion0ArchRequirements(header.plugin_arch_requirements)