summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2021-09-12 20:07:40 -0700
committerThiago Macieira <thiago.macieira@intel.com>2021-09-24 20:16:05 -0700
commit57960ab075b9e7a471c42ddea6a2abbc2994ec83 (patch)
treef2f6323330398e164a2ae67a887e88cc7337e6d0 /src
parenta03a67fbfaba28d87cccab6a7fe09ebd5da71d16 (diff)
Q{Elf,Mach}Parser: simplify the return codes
The multi-state return code was a legacy of how Arvid wrote the ELF parser code back in the day, the fact that it scanned for two different types of plugins in Qt 4 and that the metadata could exist in different places. None of that matters nowadays: who cares if the file is a corrupt binary, not a valid binary, does not have the right architecture, or has no suitable section? It's not a plugin, period. The Qt 4 plugin mechanism was removed for Qt 5.0 in commit 7443895857fdaee132c8efc643e471f02b3d0fa4 ("Remove support for Qt 4 style plugins"). Change-Id: I42eb903a916645db9900fffd16a442d800399b98 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/plugin/qelfparser_p.cpp36
-rw-r--r--src/corelib/plugin/qelfparser_p.h5
-rw-r--r--src/corelib/plugin/qlibrary.cpp56
-rw-r--r--src/corelib/plugin/qlibrary_p.h6
-rw-r--r--src/corelib/plugin/qmachparser.cpp20
-rw-r--r--src/corelib/plugin/qmachparser_p.h7
6 files changed, 57 insertions, 73 deletions
diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp
index bbcfe2f865..c5fdf79525 100644
--- a/src/corelib/plugin/qelfparser_p.cpp
+++ b/src/corelib/plugin/qelfparser_p.cpp
@@ -63,8 +63,8 @@ const char *QElfParser::parseSectionHeader(const char *data, ElfSectionHeader *s
return data;
}
-auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library,
- QLibraryPrivate *lib, qsizetype *pos, qsizetype *sectionlen) -> ScanResult
+QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library,
+ QLibraryPrivate *lib)
{
#if defined(QELFPARSER_DEBUG)
qDebug() << "QElfParser::parse " << library;
@@ -73,19 +73,19 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (fdlen < 64) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library, QLibrary::tr("file too small"));
- return NotElf;
+ return {};
}
const char *data = dataStart;
if (qstrncmp(data, "\177ELF", 4) != 0) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is not an ELF object").arg(library);
- return NotElf;
+ return {};
}
// 32 or 64 bit
if (data[4] != 1 && data[4] != 2) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd cpu architecture"));
- return Corrupt;
+ return {};
}
/* If you remove this check, to read ELF objects of a different arch, please make sure you modify the typedefs
@@ -95,7 +95,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (data[4] != ExpectedClass) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("wrong cpu architecture"));
- return Corrupt;
+ return {};
}
// endian
@@ -103,7 +103,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (data[5] != ExpectedEndianness) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd endianness"));
- return Corrupt;
+ return {};
}
data += 16 // e_ident
@@ -122,7 +122,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (e_shsize > fdlen) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shsize"));
- return Corrupt;
+ return {};
}
data += sizeof(qelfhalf_t) // e_ehsize
@@ -134,7 +134,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (e_shentsize % 4) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shentsize"));
- return Corrupt;
+ return {};
}
data += sizeof(qelfhalf_t); // e_shentsize
qelfhalf_t e_shnum = qFromUnaligned<qelfhalf_t> (data);
@@ -149,7 +149,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
nullptr, int(e_shnum)).arg(e_shentsize);
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, message);
}
- return Corrupt;
+ return {};
}
#if defined(QELFPARSER_DEBUG)
@@ -164,7 +164,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("shstrtab section header seems to be at %1")
.arg(QString::number(soff, 16)));
- return Corrupt;
+ return {};
}
parseSectionHeader(dataStart + soff, &strtab);
@@ -175,7 +175,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("string table seems to be at %1")
.arg(QString::number(strtab.offset, 16)));
- return Corrupt;
+ return {};
}
#if defined(QELFPARSER_DEBUG)
@@ -197,7 +197,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("section name %1 of %2 behind end of file")
.arg(i).arg(e_shnum));
- return Corrupt;
+ return {};
}
#if defined(QELFPARSER_DEBUG)
@@ -210,7 +210,7 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("empty .rodata. not a library."));
- return Corrupt;
+ return {};
}
#if defined(QELFPARSER_DEBUG)
qDebug()<<"section is not program data. skipped.";
@@ -223,15 +223,13 @@ auto QElfParser::parse(const char *dataStart, ulong fdlen, const QString &librar
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("missing section data. This is not a library."));
- return Corrupt;
+ return {};
}
- *pos = sh.offset;
- *sectionlen = sh.size;
- return QtMetaDataSection;
+ return { qsizetype(sh.offset), qsizetype(sh.size) };
}
s += e_shentsize;
}
- return NoQtSection;
+ return {};
}
QT_END_NAMESPACE
diff --git a/src/corelib/plugin/qelfparser_p.h b/src/corelib/plugin/qelfparser_p.h
index bd967e53ae..316d3bd0b6 100644
--- a/src/corelib/plugin/qelfparser_p.h
+++ b/src/corelib/plugin/qelfparser_p.h
@@ -52,7 +52,7 @@
//
#include <qendian.h>
-#include <private/qglobal_p.h>
+#include "qlibrary_p.h"
QT_REQUIRE_CONFIG(library);
@@ -71,7 +71,6 @@ typedef quintptr qelfaddr_t;
class QElfParser
{
public:
- enum ScanResult { QtMetaDataSection, NoQtSection, NotElf, Corrupt };
enum { ElfLittleEndian = 0, ElfBigEndian = 1 };
struct ElfSectionHeader
@@ -85,7 +84,7 @@ public:
qelfoff_t m_stringTableFileOffset;
const char *parseSectionHeader(const char* s, ElfSectionHeader *sh);
- ScanResult parse(const char *m_s, ulong fdlen, const QString &library, QLibraryPrivate *lib, qsizetype *pos, qsizetype *sectionlen);
+ QLibraryScanResult parse(const char *m_s, ulong fdlen, const QString &library, QLibraryPrivate *lib);
};
QT_END_NAMESPACE
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 2c5940f8f2..cfc7479d37 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -254,8 +254,10 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib)
constexpr qint64 MaxMemoryMapSize =
Q_INT64_C(1) << (sizeof(qsizetype) > 4 ? 40 : 29);
- qsizetype fdlen = qMin(file.size(), MaxMemoryMapSize);
- const char *filedata = reinterpret_cast<char *>(file.map(0, fdlen));
+ QLibraryScanResult r;
+ r.pos = 0;
+ r.length = qMin(file.size(), MaxMemoryMapSize);
+ const char *filedata = reinterpret_cast<char *>(file.map(0, r.length));
#ifdef Q_OS_UNIX
if (filedata == nullptr) {
@@ -274,65 +276,49 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib)
// the side of doing a regular read into memory (up to 64 MB).
data = file.read(64 * 1024 * 1024);
filedata = data.constData();
- fdlen = data.size();
+ r.length = data.size();
}
#endif
/*
- ELF and Mach-O binaries with GCC have .qplugin sections.
+ ELF and Mach-O binaries with GCC have .qtmetadata sections. Find them.
*/
bool hasMetaData = false;
- qsizetype pos = 0;
char pattern[] = "qTMETADATA ";
pattern[0] = 'Q'; // Ensure the pattern "QTMETADATA" is not found in this library should QPluginLoader ever encounter it.
const ulong plen = ulong(qstrlen(pattern));
#if defined (Q_OF_ELF)
- QElfParser::ScanResult r = QElfParser().parse(filedata, fdlen, library, lib, &pos, &fdlen);
- if (r == QElfParser::Corrupt || r == QElfParser::NotElf) {
- if (lib && qt_debug_component()) {
- qWarning("QElfParser: %ls", qUtf16Printable(lib->errorString));
- }
- return false;
- } else if (r == QElfParser::QtMetaDataSection) {
- qsizetype rel = qt_find_pattern(filedata + pos, fdlen, pattern, plen);
- if (rel < 0)
- pos = -1;
- else
- pos += rel;
- hasMetaData = true;
+ r = QElfParser().parse(filedata, r.length, library, lib);
+ if (r.length == 0) {
+ if (lib && qt_debug_component())
+ qWarning("QElfParser: %ls", qUtf16Printable(lib->errorString));
+ return false;
}
#elif defined(Q_OF_MACH_O)
{
QString errorString;
- int r = QMachOParser::parse(filedata, fdlen, library, &errorString, &pos, &fdlen);
- if (r == QMachOParser::NotSuitable) {
+ r = QMachOParser::parse(filedata, r.length, library, &errorString);
+ if (r.length == 0) {
if (qt_debug_component())
qWarning("QMachOParser: %ls", qUtf16Printable(errorString));
if (lib)
lib->errorString = errorString;
return false;
}
- // even if the metadata section was not found, the Mach-O parser will
- // at least return the boundaries of the right architecture
- qsizetype rel = qt_find_pattern(filedata + pos, fdlen, pattern, plen);
- if (rel < 0)
- pos = -1;
- else
- pos += rel;
- hasMetaData = true;
}
-#else
- pos = qt_find_pattern(filedata, fdlen, pattern, plen);
- if (pos > 0)
- hasMetaData = true;
#endif // defined(Q_OF_ELF) && defined(Q_CC_GNU)
+ if (qsizetype rel = qt_find_pattern(filedata + r.pos, r.length, pattern, plen);
+ rel >= 0) {
+ r.pos += rel;
+ hasMetaData = true;
+ }
bool ret = false;
- if (pos >= 0 && hasMetaData) {
- const char *data = filedata + pos;
+ if (r.pos >= 0 && hasMetaData) {
+ const char *data = filedata + r.pos;
QString errMsg;
- QJsonDocument doc = qJsonFromRawLibraryMetaData(data, fdlen, &errMsg);
+ QJsonDocument doc = qJsonFromRawLibraryMetaData(data, r.length, &errMsg);
if (doc.isNull()) {
qWarning("Found invalid metadata in lib %ls: %ls",
qUtf16Printable(library), qUtf16Printable(errMsg));
diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h
index 3ca544b2de..121ecae34e 100644
--- a/src/corelib/plugin/qlibrary_p.h
+++ b/src/corelib/plugin/qlibrary_p.h
@@ -68,6 +68,12 @@ QT_BEGIN_NAMESPACE
bool qt_debug_component();
+struct QLibraryScanResult
+{
+ qsizetype pos;
+ qsizetype length;
+};
+
class QLibraryStore;
class QLibraryPrivate
{
diff --git a/src/corelib/plugin/qmachparser.cpp b/src/corelib/plugin/qmachparser.cpp
index 9d0b4de4f5..db4453dffe 100644
--- a/src/corelib/plugin/qmachparser.cpp
+++ b/src/corelib/plugin/qmachparser.cpp
@@ -42,7 +42,6 @@
#if defined(Q_OF_MACH_O)
#include <qendian.h>
-#include "qlibrary_p.h"
#include <mach-o/loader.h>
#include <mach-o/fat.h>
@@ -81,15 +80,16 @@ typedef section my_section;
static const uint32_t my_magic = MH_MAGIC;
#endif
-static int ns(const QString &reason, const QString &library, QString *errorString)
+Q_DECL_COLD_FUNCTION
+static QLibraryScanResult ns(const QString &reason, const QString &library, QString *errorString)
{
if (errorString)
*errorString = QLibrary::tr("'%1' is not a valid Mach-O binary (%2)")
.arg(library, reason.isEmpty() ? QLibrary::tr("file is corrupt") : reason);
- return QMachOParser::NotSuitable;
+ return {};
}
-int QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString, qsizetype *pos, qsizetype *sectionlen)
+QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString)
{
// The minimum size of a Mach-O binary we're interested in.
// It must have a full Mach header, at least one segment and at least one
@@ -146,9 +146,7 @@ int QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QS
library, errorString);
}
- // from this point on, fdlen is specific to this architecture
// from this point on, everything is in host byte order
- *pos = reinterpret_cast<const char *>(header) - m_s;
// (re-)check the CPU type
// ### should we check the CPU subtype? Maybe on ARM?
@@ -197,9 +195,8 @@ int QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QS
|| Q_UNLIKELY(fdlen < sect[j].offset + sect[j].size))
return ns(QString(), library, errorString);
- *pos += sect[j].offset;
- *sectionlen = sect[j].size;
- return QtMetaDataSection;
+ qsizetype pos = reinterpret_cast<const char *>(header) - m_s + sect[j].offset;
+ return { pos, qsizetype(sect[j].size) };
}
}
@@ -207,11 +204,10 @@ int QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QS
seg = reinterpret_cast<const my_segment_command *>(reinterpret_cast<const char *>(seg) + seg->cmdsize);
}
-// // No Qt section was found, but at least we know that where the proper architecture's boundaries are
-// return NoQtSection;
+ // No .qtmetadata section was found
if (errorString)
*errorString = QLibrary::tr("'%1' is not a Qt plugin").arg(library);
- return NotSuitable;
+ return {};
}
QT_END_NAMESPACE
diff --git a/src/corelib/plugin/qmachparser_p.h b/src/corelib/plugin/qmachparser_p.h
index 290b68876f..499c63aa94 100644
--- a/src/corelib/plugin/qmachparser_p.h
+++ b/src/corelib/plugin/qmachparser_p.h
@@ -51,8 +51,7 @@
// We mean it.
//
-#include <qendian.h>
-#include <private/qglobal_p.h>
+#include "qlibrary_p.h"
QT_REQUIRE_CONFIG(library);
@@ -66,8 +65,8 @@ class QLibraryPrivate;
class Q_AUTOTEST_EXPORT QMachOParser
{
public:
- enum { QtMetaDataSection, NoQtSection, NotSuitable };
- static int parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString, qsizetype *pos, qsizetype *sectionlen);
+ static QLibraryScanResult parse(const char *m_s, ulong fdlen, const QString &library,
+ QString *errorString);
};
QT_END_NAMESPACE