diff options
-rw-r--r-- | src/corelib/plugin/qelfparser_p.cpp | 53 | ||||
-rw-r--r-- | src/corelib/plugin/qelfparser_p.h | 2 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 25 | ||||
-rw-r--r-- | src/corelib/plugin/qmachparser.cpp | 37 | ||||
-rw-r--r-- | src/corelib/plugin/qmachparser_p.h | 3 | ||||
-rw-r--r-- | tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp | 7 |
6 files changed, 55 insertions, 72 deletions
diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp index c5fdf79525..c9b49c1570 100644 --- a/src/corelib/plugin/qelfparser_p.cpp +++ b/src/corelib/plugin/qelfparser_p.cpp @@ -63,28 +63,24 @@ const char *QElfParser::parseSectionHeader(const char *data, ElfSectionHeader *s return data; } -QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library, - QLibraryPrivate *lib) +QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, QString *errMsg) { #if defined(QELFPARSER_DEBUG) qDebug() << "QElfParser::parse " << library; #endif if (fdlen < 64) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library, QLibrary::tr("file too small")); + *errMsg = QLibrary::tr("'%1' is not an ELF object (%2)").arg(*errMsg, QLibrary::tr("file too small")); 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); + *errMsg = QLibrary::tr("'%1' is not an ELF object").arg(*errMsg); 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")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, QLibrary::tr("odd cpu architecture")); return {}; } @@ -93,16 +89,14 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q */ constexpr int ExpectedClass = (sizeof(void *) == 4) ? 1 : 2; if (data[4] != ExpectedClass) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("wrong cpu architecture")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, QLibrary::tr("wrong cpu architecture")); return {}; } // endian constexpr int ExpectedEndianness = (Q_BYTE_ORDER == Q_LITTLE_ENDIAN) ? 1 : 2; if (data[5] != ExpectedEndianness) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd endianness")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, QLibrary::tr("odd endianness")); return {}; } @@ -120,8 +114,7 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q qelfhalf_t e_shsize = qFromUnaligned<qelfhalf_t> (data); if (e_shsize > fdlen) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shsize")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, QLibrary::tr("unexpected e_shsize")); return {}; } @@ -132,8 +125,7 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q qelfhalf_t e_shentsize = qFromUnaligned<qelfhalf_t> (data); if (e_shentsize % 4) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shentsize")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, QLibrary::tr("unexpected e_shentsize")); return {}; } data += sizeof(qelfhalf_t); // e_shentsize @@ -143,12 +135,10 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q data += sizeof(qelfhalf_t); // e_shtrndx if ((quint32)(e_shnum * e_shentsize) > fdlen) { - if (lib) { const QString message = QLibrary::tr("announced %n section(s), each %1 byte(s), exceed file size", nullptr, int(e_shnum)).arg(e_shentsize); - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, message); - } + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(*errMsg, message); return {}; } @@ -160,9 +150,8 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q qulonglong soff = e_shoff + qelfword_t(e_shentsize) * qelfword_t(e_shtrndx); if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)") - .arg(library, QLibrary::tr("shstrtab section header seems to be at %1") + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)") + .arg(*errMsg, QLibrary::tr("shstrtab section header seems to be at %1") .arg(QString::number(soff, 16))); return {}; } @@ -171,9 +160,8 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q m_stringTableFileOffset = strtab.offset; if ((quint32)(strtab.offset + strtab.size) > fdlen || strtab.offset == 0) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)") - .arg(library, QLibrary::tr("string table seems to be at %1") + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)") + .arg(*errMsg, QLibrary::tr("string table seems to be at %1") .arg(QString::number(strtab.offset, 16))); return {}; } @@ -193,9 +181,8 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q const char *shnam = dataStart + m_stringTableFileOffset + sh.name; if (m_stringTableFileOffset + sh.name > fdlen) { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)") - .arg(library, QLibrary::tr("section name %1 of %2 behind end of file") + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)") + .arg(*errMsg, QLibrary::tr("section name %1 of %2 behind end of file") .arg(i).arg(e_shnum)); return {}; } @@ -207,9 +194,8 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q if (qstrcmp(shnam, ".qtmetadata") == 0 ) { if (!(sh.type & 0x1)) { if (shnam[1] == 'r') { - if (lib) - lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)") - .arg(library, QLibrary::tr("empty .rodata. not a library.")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)") + .arg(*errMsg, QLibrary::tr("empty .rodata. not a library.")); return {}; } #if defined(QELFPARSER_DEBUG) @@ -220,9 +206,8 @@ QLibraryScanResult QElfParser::parse(const char *dataStart, ulong fdlen, const Q } if (sh.offset == 0 || (sh.offset + sh.size) > fdlen || sh.size < 1) { - 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.")); + *errMsg = QLibrary::tr("'%1' is an invalid ELF object (%2)") + .arg(*errMsg, QLibrary::tr("missing section data. This is not a library.")); return {}; } return { qsizetype(sh.offset), qsizetype(sh.size) }; diff --git a/src/corelib/plugin/qelfparser_p.h b/src/corelib/plugin/qelfparser_p.h index 316d3bd0b6..d91b1d4867 100644 --- a/src/corelib/plugin/qelfparser_p.h +++ b/src/corelib/plugin/qelfparser_p.h @@ -84,7 +84,7 @@ public: qelfoff_t m_stringTableFileOffset; const char *parseSectionHeader(const char* s, ElfSectionHeader *sh); - QLibraryScanResult parse(const char *m_s, ulong fdlen, const QString &library, QLibraryPrivate *lib); + QLibraryScanResult parse(const char *m_s, ulong fdlen, QString *errMsg); }; QT_END_NAMESPACE diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index befe784c05..a99ee57a92 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -255,31 +255,30 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) /* ELF and Mach-O binaries with GCC have .qtmetadata sections. Find them. */ + QString errMsg = library; #if defined (Q_OF_ELF) - r = QElfParser().parse(filedata, r.length, library, lib); + r = QElfParser().parse(filedata, r.length, &errMsg); if (r.length == 0) { if (lib && qt_debug_component()) - qWarning("QElfParser: %ls", qUtf16Printable(lib->errorString)); + qWarning("QElfParser: %ls", qUtf16Printable(errMsg)); + if (lib) + lib->errorString = errMsg; return false; } #elif defined(Q_OF_MACH_O) - { - QString errorString; - 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; - } + r = QMachOParser::parse(filedata, r.length, &errMsg); + if (r.length == 0) { + if (qt_debug_component()) + qWarning("QMachOParser: %ls", qUtf16Printable(errMsg)); + if (lib) + lib->errorString = errMsg; + return false; } #endif // defined(Q_OF_ELF) && defined(Q_CC_GNU) if (qsizetype rel = qt_find_pattern(filedata + r.pos, r.length); rel >= 0) { const char *data = filedata + r.pos + rel; - QString errMsg; QJsonDocument doc = qJsonFromRawLibraryMetaData(data, r.length, &errMsg); if (doc.isNull()) { qWarning("Found invalid metadata in lib %ls: %ls", diff --git a/src/corelib/plugin/qmachparser.cpp b/src/corelib/plugin/qmachparser.cpp index db4453dffe..ef989f2ac0 100644 --- a/src/corelib/plugin/qmachparser.cpp +++ b/src/corelib/plugin/qmachparser.cpp @@ -81,15 +81,14 @@ static const uint32_t my_magic = MH_MAGIC; #endif Q_DECL_COLD_FUNCTION -static QLibraryScanResult ns(const QString &reason, const QString &library, QString *errorString) +static QLibraryScanResult notfound(const QString &reason, 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); + *errorString = QLibrary::tr("'%1' is not a valid Mach-O binary (%2)") + .arg(*errorString, reason.isEmpty() ? QLibrary::tr("file is corrupt") : reason); return {}; } -QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QString &library, QString *errorString) +QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, 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 @@ -100,7 +99,7 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr static const size_t MinFatHeaderSize = sizeof(fat_header) + 2 * sizeof(fat_arch); if (Q_UNLIKELY(fdlen < MinFileSize)) - return ns(QLibrary::tr("file too small"), library, errorString); + return notfound(QLibrary::tr("file too small"), errorString); // find out if this is a fat Mach-O binary first const my_mach_header *header = nullptr; @@ -109,12 +108,12 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr // find our architecture in the binary const fat_arch *arch = reinterpret_cast<const fat_arch *>(fat + 1); if (Q_UNLIKELY(fdlen < MinFatHeaderSize)) { - return ns(QLibrary::tr("file too small"), library, errorString); + return notfound(QLibrary::tr("file too small"), errorString); } int count = qFromBigEndian(fat->nfat_arch); if (Q_UNLIKELY(fdlen < sizeof(*fat) + sizeof(*arch) * count)) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); for (int i = 0; i < count; ++i) { if (arch[i].cputype == qToBigEndian(my_cputype)) { @@ -123,7 +122,7 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr uint32_t offset = qFromBigEndian(arch[i].offset); if (Q_UNLIKELY(size > fdlen) || Q_UNLIKELY(offset > fdlen) || Q_UNLIKELY(size + offset > fdlen) || Q_UNLIKELY(size < MinFileSize)) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); header = reinterpret_cast<const my_mach_header *>(m_s + offset); fdlen = size; @@ -131,19 +130,19 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr } } if (!header) - return ns(QLibrary::tr("no suitable architecture in fat binary"), library, errorString); + return notfound(QLibrary::tr("no suitable architecture in fat binary"), errorString); // check the magic again if (Q_UNLIKELY(header->magic != my_magic)) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); } else { header = reinterpret_cast<const my_mach_header *>(m_s); fat = 0; // check magic if (header->magic != my_magic) - return ns(QLibrary::tr("invalid magic %1").arg(qFromBigEndian(header->magic), 8, 16, QLatin1Char('0')), - library, errorString); + return notfound(QLibrary::tr("invalid magic %1").arg(qFromBigEndian(header->magic), 8, 16, QLatin1Char('0')), + errorString); } // from this point on, everything is in host byte order @@ -152,13 +151,13 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr // ### should we check the CPU subtype? Maybe on ARM? if (header->cputype != my_cputype) { if (fat) - return ns(QString(), library, errorString); - return ns(QLibrary::tr("wrong architecture"), library, errorString); + return notfound(QString(), errorString); + return notfound(QLibrary::tr("wrong architecture"), errorString); } // check the file type if (Q_UNLIKELY(header->filetype != MH_BUNDLE && header->filetype != MH_DYLIB)) - return ns(QLibrary::tr("not a dynamic library"), library, errorString); + return notfound(QLibrary::tr("not a dynamic library"), errorString); // find the __TEXT segment, "qtmetadata" section const my_segment_command *seg = reinterpret_cast<const my_segment_command *>(header + 1); @@ -169,14 +168,14 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr // We're sure that the file size includes at least one load command // but we have to check anyway if we're past the first if (Q_UNLIKELY(fdlen < minsize + sizeof(load_command))) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); // cmdsize can't be trusted until validated // so check it against fdlen anyway // (these are unsigned operations, with overflow behavior specified in the standard) minsize += seg->cmdsize; if (Q_UNLIKELY(fdlen < minsize) || Q_UNLIKELY(fdlen < seg->cmdsize)) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); const uint32_t MyLoadCommand = sizeof(void *) > 4 ? LC_SEGMENT_64 : LC_SEGMENT; if (seg->cmd != MyLoadCommand) @@ -193,7 +192,7 @@ QLibraryScanResult QMachOParser::parse(const char *m_s, ulong fdlen, const QStr // found it! if (Q_UNLIKELY(fdlen < sect[j].offset) || Q_UNLIKELY(fdlen < sect[j].size) || Q_UNLIKELY(fdlen < sect[j].offset + sect[j].size)) - return ns(QString(), library, errorString); + return notfound(QString(), errorString); qsizetype pos = reinterpret_cast<const char *>(header) - m_s + sect[j].offset; return { pos, qsizetype(sect[j].size) }; diff --git a/src/corelib/plugin/qmachparser_p.h b/src/corelib/plugin/qmachparser_p.h index 499c63aa94..9e0375c6cb 100644 --- a/src/corelib/plugin/qmachparser_p.h +++ b/src/corelib/plugin/qmachparser_p.h @@ -65,8 +65,7 @@ class QLibraryPrivate; class Q_AUTOTEST_EXPORT QMachOParser { public: - static QLibraryScanResult parse(const char *m_s, ulong fdlen, const QString &library, - QString *errorString); + static QLibraryScanResult parse(const char *m_s, ulong fdlen, QString *errorString); }; QT_END_NAMESPACE diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp index 839a26e3c9..53fc0b80e3 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp @@ -374,8 +374,8 @@ void tst_QPluginLoader::loadMachO() QVERIFY(f.open(QIODevice::ReadOnly)); QByteArray data = f.readAll(); - QString errorString; - QLibraryScanResult r = QMachOParser::parse(data.constData(), data.size(), f.fileName(), &errorString); + QString errorString = f.fileName(); + QLibraryScanResult r = QMachOParser::parse(data.constData(), data.size(), &errorString); QFETCH(bool, success); if (success) { @@ -397,7 +397,8 @@ void tst_QPluginLoader::loadMachO() ulong offeredlen = r.pos; do { --offeredlen; - r = QMachOParser::parse(data.constData(), offeredlen, f.fileName(), &errorString); + errorString = f.fileName(); + r = QMachOParser::parse(data.constData(), offeredlen, &errorString); QVERIFY2(r.length == 0, qPrintable(QString("Failed at size 0x%1").arg(offeredlen, 0, 16))); } while (offeredlen); #endif |