Q{Elf,Mach}Parser: harmonize the arguments passed
Both functions took a QString for the input file name, but while the ELF parser had an optional QLibrary pointer (which was never null) where to store the error string, the Mach-O parser received a pointer to a QString. So make both of them take a single in/out QString pointer, which has the file name on input and is cheap for us because of COW. Drive-by fix the name of the static function in qmachparser.cpp from "ns" (which stood for "not suitable") to "notfound". Change-Id: I3eb1bd30e0124f89a052fffd16a8182f4f8541c3 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
349fb14c1d
commit
461084b6c4
@ -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) };
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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) };
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user