androiddeplyqt: port to RAII handling of popen()ed FILE*s
Coverity found several FILE* leaks (since fixed) in the code, so make sure that those can't happen anymore, by using unique_ptr to manage the pclose() of the openProcess() FILE handles. Keep the actual type of the unique_ptr instantiation local to openProcess() so that creation and destruction are defined close together, notwithstanding the occasional explicit pclose() calls to capture the error code. As a drive-by, port a naked popen() to openProcess(), make some variables const and replace 0 with nullptr. Pick-to: 6.7 6.5 Coverity-Id: 378357 Coverity-Id: 378442 Change-Id: I2b06b99cba1e4eb5b8963a9c5d2cb398eb25a8b3 Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
parent
48cc43a1e0
commit
0a48730d08
@ -44,15 +44,16 @@ static const bool mustReadOutputAnyway = true; // pclose seems to return the wro
|
|||||||
|
|
||||||
static QStringList dependenciesForDepfile;
|
static QStringList dependenciesForDepfile;
|
||||||
|
|
||||||
FILE *openProcess(const QString &command)
|
auto openProcess(const QString &command)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_WIN32)
|
#if defined(Q_OS_WIN32)
|
||||||
QString processedCommand = u'\"' + command + u'\"';
|
QString processedCommand = u'\"' + command + u'\"';
|
||||||
#else
|
#else
|
||||||
const QString& processedCommand = command;
|
const QString& processedCommand = command;
|
||||||
#endif
|
#endif
|
||||||
|
struct Closer { void operator()(FILE *proc) const { if (proc) (void)pclose(proc); } };
|
||||||
return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ);
|
using UP = std::unique_ptr<FILE, Closer>;
|
||||||
|
return UP{popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ)};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QtDependency
|
struct QtDependency
|
||||||
@ -310,23 +311,21 @@ QString fileArchitecture(const Options &options, const QString &path)
|
|||||||
|
|
||||||
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(path));
|
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(path));
|
||||||
|
|
||||||
FILE *readElfCommand = openProcess(readElf);
|
auto readElfCommand = openProcess(readElf);
|
||||||
if (!readElfCommand) {
|
if (!readElfCommand) {
|
||||||
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
|
while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) {
|
||||||
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
|
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
|
||||||
line = line.trimmed();
|
line = line.trimmed();
|
||||||
if (line.startsWith("Arch: ")) {
|
if (line.startsWith("Arch: ")) {
|
||||||
auto it = elfArchitectures.find(line.mid(6));
|
auto it = elfArchitectures.find(line.mid(6));
|
||||||
pclose(readElfCommand);
|
|
||||||
return it != elfArchitectures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
|
return it != elfArchitectures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pclose(readElfCommand);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2014,7 +2013,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
|||||||
|
|
||||||
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(fileName));
|
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(fileName));
|
||||||
|
|
||||||
FILE *readElfCommand = openProcess(readElf);
|
auto readElfCommand = openProcess(readElf);
|
||||||
if (!readElfCommand) {
|
if (!readElfCommand) {
|
||||||
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
||||||
return QStringList();
|
return QStringList();
|
||||||
@ -2024,7 +2023,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
|||||||
|
|
||||||
bool readLibs = false;
|
bool readLibs = false;
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
|
while (fgets(buffer, sizeof(buffer), readElfCommand.get()) != nullptr) {
|
||||||
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
|
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
|
||||||
QString library;
|
QString library;
|
||||||
line = line.trimmed();
|
line = line.trimmed();
|
||||||
@ -2034,7 +2033,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
|||||||
if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
|
if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
|
fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
|
||||||
pclose(readElfCommand);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2049,8 +2047,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
|||||||
ret += libraryName;
|
ret += libraryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
pclose(readElfCommand);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2188,7 +2184,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
|||||||
qmlImportScanner.toLocal8Bit().constData());
|
qmlImportScanner.toLocal8Bit().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), QT_POPEN_READ);
|
auto qmlImportScannerCommand = openProcess(qmlImportScanner);
|
||||||
if (qmlImportScannerCommand == 0) {
|
if (qmlImportScannerCommand == 0) {
|
||||||
fprintf(stderr, "Couldn't run qmlimportscanner.\n");
|
fprintf(stderr, "Couldn't run qmlimportscanner.\n");
|
||||||
return false;
|
return false;
|
||||||
@ -2196,13 +2192,12 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
|||||||
|
|
||||||
QByteArray output;
|
QByteArray output;
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0)
|
while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand.get()) != nullptr)
|
||||||
output += QByteArray(buffer, qstrlen(buffer));
|
output += QByteArray(buffer, qstrlen(buffer));
|
||||||
|
|
||||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
|
QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
|
||||||
if (jsonDocument.isNull()) {
|
if (jsonDocument.isNull()) {
|
||||||
fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
|
fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
|
||||||
pclose(qmlImportScannerCommand);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2211,7 +2206,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
|||||||
QJsonValue value = jsonArray.at(i);
|
QJsonValue value = jsonArray.at(i);
|
||||||
if (!value.isObject()) {
|
if (!value.isObject()) {
|
||||||
fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
|
fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
|
||||||
pclose(qmlImportScannerCommand);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2257,7 +2251,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
|||||||
|
|
||||||
if (importPathOfThisImport.isEmpty()) {
|
if (importPathOfThisImport.isEmpty()) {
|
||||||
fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
|
fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
|
||||||
pclose(qmlImportScannerCommand);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2325,7 +2318,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pclose(qmlImportScannerCommand);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2344,17 +2336,17 @@ bool runCommand(const Options &options, const QString &command)
|
|||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "Running command '%s'\n", qPrintable(command));
|
fprintf(stdout, "Running command '%s'\n", qPrintable(command));
|
||||||
|
|
||||||
FILE *runCommand = openProcess(command);
|
auto runCommand = openProcess(command);
|
||||||
if (runCommand == nullptr) {
|
if (runCommand == nullptr) {
|
||||||
fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command));
|
fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
while (fgets(buffer, sizeof(buffer), runCommand) != nullptr) {
|
while (fgets(buffer, sizeof(buffer), runCommand.get()) != nullptr) {
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
}
|
}
|
||||||
pclose(runCommand);
|
runCommand.reset();
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
return true;
|
return true;
|
||||||
@ -2505,7 +2497,8 @@ bool containsApplicationBinary(Options *options)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *runAdb(const Options &options, const QString &arguments)
|
auto runAdb(const Options &options, const QString &arguments)
|
||||||
|
-> decltype(openProcess({}))
|
||||||
{
|
{
|
||||||
QString adb = execSuffixAppended(options.sdkPath + "/platform-tools/adb"_L1);
|
QString adb = execSuffixAppended(options.sdkPath + "/platform-tools/adb"_L1);
|
||||||
if (!QFile::exists(adb)) {
|
if (!QFile::exists(adb)) {
|
||||||
@ -2521,7 +2514,7 @@ FILE *runAdb(const Options &options, const QString &arguments)
|
|||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
|
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
|
||||||
|
|
||||||
FILE *adbCommand = openProcess(adb);
|
auto adbCommand = openProcess(adb);
|
||||||
if (adbCommand == 0) {
|
if (adbCommand == 0) {
|
||||||
fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb));
|
fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb));
|
||||||
return 0;
|
return 0;
|
||||||
@ -2864,19 +2857,19 @@ bool buildAndroidProject(const Options &options)
|
|||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
commandLine += " --info"_L1;
|
commandLine += " --info"_L1;
|
||||||
|
|
||||||
FILE *gradleCommand = openProcess(commandLine);
|
auto gradleCommand = openProcess(commandLine);
|
||||||
if (gradleCommand == 0) {
|
if (gradleCommand == 0) {
|
||||||
fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine));
|
fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) {
|
while (fgets(buffer, sizeof(buffer), gradleCommand.get()) != nullptr) {
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorCode = pclose(gradleCommand);
|
const int errorCode = pclose(gradleCommand.release());
|
||||||
if (errorCode != 0) {
|
if (errorCode != 0) {
|
||||||
fprintf(stderr, "Building the android package failed!\n");
|
fprintf(stderr, "Building the android package failed!\n");
|
||||||
if (!options.verbose)
|
if (!options.verbose)
|
||||||
@ -2902,18 +2895,18 @@ bool uninstallApk(const Options &options)
|
|||||||
fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName));
|
fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName));
|
||||||
|
|
||||||
|
|
||||||
FILE *adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
|
auto adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
|
||||||
if (adbCommand == 0)
|
if (adbCommand == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (options.verbose || mustReadOutputAnyway) {
|
if (options.verbose || mustReadOutputAnyway) {
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
|
while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int returnCode = pclose(adbCommand);
|
const int returnCode = pclose(adbCommand.release());
|
||||||
if (returnCode != 0) {
|
if (returnCode != 0) {
|
||||||
fprintf(stderr, "Warning: Uninstall failed!\n");
|
fprintf(stderr, "Warning: Uninstall failed!\n");
|
||||||
if (!options.verbose)
|
if (!options.verbose)
|
||||||
@ -2971,20 +2964,20 @@ bool installApk(const Options &options)
|
|||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "Installing Android package to device.\n");
|
fprintf(stdout, "Installing Android package to device.\n");
|
||||||
|
|
||||||
FILE *adbCommand = runAdb(options, " install -r "_L1
|
auto adbCommand = runAdb(options, " install -r "_L1
|
||||||
+ packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
|
+ packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
|
||||||
: SignedAPK));
|
: SignedAPK));
|
||||||
if (adbCommand == 0)
|
if (adbCommand == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (options.verbose || mustReadOutputAnyway) {
|
if (options.verbose || mustReadOutputAnyway) {
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
|
while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
|
||||||
if (options.verbose)
|
if (options.verbose)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int returnCode = pclose(adbCommand);
|
const int returnCode = pclose(adbCommand.release());
|
||||||
if (returnCode != 0) {
|
if (returnCode != 0) {
|
||||||
fprintf(stderr, "Installing to device failed!\n");
|
fprintf(stderr, "Installing to device failed!\n");
|
||||||
if (!options.verbose)
|
if (!options.verbose)
|
||||||
@ -3102,7 +3095,7 @@ bool signAAB(const Options &options)
|
|||||||
QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file))
|
QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file))
|
||||||
.arg(shellQuote(options.keyStoreAlias));
|
.arg(shellQuote(options.keyStoreAlias));
|
||||||
|
|
||||||
FILE *jarSignerCommand = openProcess(command);
|
auto jarSignerCommand = openProcess(command);
|
||||||
if (jarSignerCommand == 0) {
|
if (jarSignerCommand == 0) {
|
||||||
fprintf(stderr, "Couldn't run jarsigner.\n");
|
fprintf(stderr, "Couldn't run jarsigner.\n");
|
||||||
return false;
|
return false;
|
||||||
@ -3110,11 +3103,11 @@ bool signAAB(const Options &options)
|
|||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
|
while (fgets(buffer, sizeof(buffer), jarSignerCommand.get()) != nullptr)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorCode = pclose(jarSignerCommand);
|
const int errorCode = pclose(jarSignerCommand.release());
|
||||||
if (errorCode != 0) {
|
if (errorCode != 0) {
|
||||||
fprintf(stderr, "jarsigner command failed.\n");
|
fprintf(stderr, "jarsigner command failed.\n");
|
||||||
if (!options.verbose)
|
if (!options.verbose)
|
||||||
@ -3142,17 +3135,17 @@ bool signPackage(const Options &options)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto zipalignRunner = [](const QString &zipAlignCommandLine) {
|
auto zipalignRunner = [](const QString &zipAlignCommandLine) {
|
||||||
FILE *zipAlignCommand = openProcess(zipAlignCommandLine);
|
auto zipAlignCommand = openProcess(zipAlignCommandLine);
|
||||||
if (zipAlignCommand == 0) {
|
if (zipAlignCommand == 0) {
|
||||||
fprintf(stderr, "Couldn't run zipalign.\n");
|
fprintf(stderr, "Couldn't run zipalign.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
|
while (fgets(buffer, sizeof(buffer), zipAlignCommand.get()) != nullptr)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
|
|
||||||
return pclose(zipAlignCommand) == 0;
|
return pclose(zipAlignCommand.release()) == 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const QString verifyZipAlignCommandLine =
|
const QString verifyZipAlignCommandLine =
|
||||||
@ -3209,17 +3202,17 @@ bool signPackage(const Options &options)
|
|||||||
apkSignCommand += " %1"_L1.arg(shellQuote(packagePath(options, SignedAPK)));
|
apkSignCommand += " %1"_L1.arg(shellQuote(packagePath(options, SignedAPK)));
|
||||||
|
|
||||||
auto apkSignerRunner = [](const QString &command, bool verbose) {
|
auto apkSignerRunner = [](const QString &command, bool verbose) {
|
||||||
FILE *apkSigner = openProcess(command);
|
auto apkSigner = openProcess(command);
|
||||||
if (apkSigner == 0) {
|
if (apkSigner == 0) {
|
||||||
fprintf(stderr, "Couldn't run apksigner.\n");
|
fprintf(stderr, "Couldn't run apksigner.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
while (fgets(buffer, sizeof(buffer), apkSigner) != 0)
|
while (fgets(buffer, sizeof(buffer), apkSigner.get()) != nullptr)
|
||||||
fprintf(stdout, "%s", buffer);
|
fprintf(stdout, "%s", buffer);
|
||||||
|
|
||||||
int errorCode = pclose(apkSigner);
|
const int errorCode = pclose(apkSigner.release());
|
||||||
if (errorCode != 0) {
|
if (errorCode != 0) {
|
||||||
fprintf(stderr, "apksigner command failed.\n");
|
fprintf(stderr, "apksigner command failed.\n");
|
||||||
if (!verbose)
|
if (!verbose)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user