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;
|
||||
|
||||
FILE *openProcess(const QString &command)
|
||||
auto openProcess(const QString &command)
|
||||
{
|
||||
#if defined(Q_OS_WIN32)
|
||||
QString processedCommand = u'\"' + command + u'\"';
|
||||
#else
|
||||
const QString& processedCommand = command;
|
||||
#endif
|
||||
|
||||
return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ);
|
||||
struct Closer { void operator()(FILE *proc) const { if (proc) (void)pclose(proc); } };
|
||||
using UP = std::unique_ptr<FILE, Closer>;
|
||||
return UP{popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ)};
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
FILE *readElfCommand = openProcess(readElf);
|
||||
auto readElfCommand = openProcess(readElf);
|
||||
if (!readElfCommand) {
|
||||
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
||||
return {};
|
||||
}
|
||||
|
||||
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));
|
||||
line = line.trimmed();
|
||||
if (line.startsWith("Arch: ")) {
|
||||
auto it = elfArchitectures.find(line.mid(6));
|
||||
pclose(readElfCommand);
|
||||
return it != elfArchitectures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
|
||||
}
|
||||
}
|
||||
pclose(readElfCommand);
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -2014,7 +2013,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
||||
|
||||
readElf = "%1 --needed-libs %2"_L1.arg(shellQuote(readElf), shellQuote(fileName));
|
||||
|
||||
FILE *readElfCommand = openProcess(readElf);
|
||||
auto readElfCommand = openProcess(readElf);
|
||||
if (!readElfCommand) {
|
||||
fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
|
||||
return QStringList();
|
||||
@ -2024,7 +2023,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
||||
|
||||
bool readLibs = false;
|
||||
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));
|
||||
QString library;
|
||||
line = line.trimmed();
|
||||
@ -2034,7 +2033,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
||||
if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
|
||||
pclose(readElfCommand);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@ -2049,8 +2047,6 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
|
||||
ret += libraryName;
|
||||
}
|
||||
|
||||
pclose(readElfCommand);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2188,7 +2184,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
||||
qmlImportScanner.toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), QT_POPEN_READ);
|
||||
auto qmlImportScannerCommand = openProcess(qmlImportScanner);
|
||||
if (qmlImportScannerCommand == 0) {
|
||||
fprintf(stderr, "Couldn't run qmlimportscanner.\n");
|
||||
return false;
|
||||
@ -2196,13 +2192,12 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
||||
|
||||
QByteArray output;
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand.get()) != nullptr)
|
||||
output += QByteArray(buffer, qstrlen(buffer));
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
|
||||
if (jsonDocument.isNull()) {
|
||||
fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
|
||||
pclose(qmlImportScannerCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2211,7 +2206,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
||||
QJsonValue value = jsonArray.at(i);
|
||||
if (!value.isObject()) {
|
||||
fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
|
||||
pclose(qmlImportScannerCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2257,7 +2251,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
||||
|
||||
if (importPathOfThisImport.isEmpty()) {
|
||||
fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
|
||||
pclose(qmlImportScannerCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2325,7 +2318,6 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
pclose(qmlImportScannerCommand);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2344,17 +2336,17 @@ bool runCommand(const Options &options, const QString &command)
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "Running command '%s'\n", qPrintable(command));
|
||||
|
||||
FILE *runCommand = openProcess(command);
|
||||
auto runCommand = openProcess(command);
|
||||
if (runCommand == nullptr) {
|
||||
fprintf(stderr, "Cannot run command '%s'\n", qPrintable(command));
|
||||
return false;
|
||||
}
|
||||
char buffer[4096];
|
||||
while (fgets(buffer, sizeof(buffer), runCommand) != nullptr) {
|
||||
while (fgets(buffer, sizeof(buffer), runCommand.get()) != nullptr) {
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
}
|
||||
pclose(runCommand);
|
||||
runCommand.reset();
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
return true;
|
||||
@ -2505,7 +2497,8 @@ bool containsApplicationBinary(Options *options)
|
||||
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);
|
||||
if (!QFile::exists(adb)) {
|
||||
@ -2521,7 +2514,7 @@ FILE *runAdb(const Options &options, const QString &arguments)
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
|
||||
|
||||
FILE *adbCommand = openProcess(adb);
|
||||
auto adbCommand = openProcess(adb);
|
||||
if (adbCommand == 0) {
|
||||
fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb));
|
||||
return 0;
|
||||
@ -2864,19 +2857,19 @@ bool buildAndroidProject(const Options &options)
|
||||
if (options.verbose)
|
||||
commandLine += " --info"_L1;
|
||||
|
||||
FILE *gradleCommand = openProcess(commandLine);
|
||||
auto gradleCommand = openProcess(commandLine);
|
||||
if (gradleCommand == 0) {
|
||||
fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine));
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) {
|
||||
while (fgets(buffer, sizeof(buffer), gradleCommand.get()) != nullptr) {
|
||||
fprintf(stdout, "%s", buffer);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int errorCode = pclose(gradleCommand);
|
||||
const int errorCode = pclose(gradleCommand.release());
|
||||
if (errorCode != 0) {
|
||||
fprintf(stderr, "Building the android package failed!\n");
|
||||
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));
|
||||
|
||||
|
||||
FILE *adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
|
||||
auto adbCommand = runAdb(options, " uninstall "_L1 + shellQuote(options.packageName));
|
||||
if (adbCommand == 0)
|
||||
return false;
|
||||
|
||||
if (options.verbose || mustReadOutputAnyway) {
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
}
|
||||
|
||||
int returnCode = pclose(adbCommand);
|
||||
const int returnCode = pclose(adbCommand.release());
|
||||
if (returnCode != 0) {
|
||||
fprintf(stderr, "Warning: Uninstall failed!\n");
|
||||
if (!options.verbose)
|
||||
@ -2971,20 +2964,20 @@ bool installApk(const Options &options)
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "Installing Android package to device.\n");
|
||||
|
||||
FILE *adbCommand = runAdb(options, " install -r "_L1
|
||||
+ packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
|
||||
: SignedAPK));
|
||||
auto adbCommand = runAdb(options, " install -r "_L1
|
||||
+ packagePath(options, options.keyStore.isEmpty() ? UnsignedAPK
|
||||
: SignedAPK));
|
||||
if (adbCommand == 0)
|
||||
return false;
|
||||
|
||||
if (options.verbose || mustReadOutputAnyway) {
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), adbCommand.get()) != nullptr)
|
||||
if (options.verbose)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
}
|
||||
|
||||
int returnCode = pclose(adbCommand);
|
||||
const int returnCode = pclose(adbCommand.release());
|
||||
if (returnCode != 0) {
|
||||
fprintf(stderr, "Installing to device failed!\n");
|
||||
if (!options.verbose)
|
||||
@ -3102,7 +3095,7 @@ bool signAAB(const Options &options)
|
||||
QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file))
|
||||
.arg(shellQuote(options.keyStoreAlias));
|
||||
|
||||
FILE *jarSignerCommand = openProcess(command);
|
||||
auto jarSignerCommand = openProcess(command);
|
||||
if (jarSignerCommand == 0) {
|
||||
fprintf(stderr, "Couldn't run jarsigner.\n");
|
||||
return false;
|
||||
@ -3110,11 +3103,11 @@ bool signAAB(const Options &options)
|
||||
|
||||
if (options.verbose) {
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), jarSignerCommand.get()) != nullptr)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
}
|
||||
|
||||
int errorCode = pclose(jarSignerCommand);
|
||||
const int errorCode = pclose(jarSignerCommand.release());
|
||||
if (errorCode != 0) {
|
||||
fprintf(stderr, "jarsigner command failed.\n");
|
||||
if (!options.verbose)
|
||||
@ -3142,17 +3135,17 @@ bool signPackage(const Options &options)
|
||||
return false;
|
||||
|
||||
auto zipalignRunner = [](const QString &zipAlignCommandLine) {
|
||||
FILE *zipAlignCommand = openProcess(zipAlignCommandLine);
|
||||
auto zipAlignCommand = openProcess(zipAlignCommandLine);
|
||||
if (zipAlignCommand == 0) {
|
||||
fprintf(stderr, "Couldn't run zipalign.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), zipAlignCommand.get()) != nullptr)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
|
||||
return pclose(zipAlignCommand) == 0;
|
||||
return pclose(zipAlignCommand.release()) == 0;
|
||||
};
|
||||
|
||||
const QString verifyZipAlignCommandLine =
|
||||
@ -3209,17 +3202,17 @@ bool signPackage(const Options &options)
|
||||
apkSignCommand += " %1"_L1.arg(shellQuote(packagePath(options, SignedAPK)));
|
||||
|
||||
auto apkSignerRunner = [](const QString &command, bool verbose) {
|
||||
FILE *apkSigner = openProcess(command);
|
||||
auto apkSigner = openProcess(command);
|
||||
if (apkSigner == 0) {
|
||||
fprintf(stderr, "Couldn't run apksigner.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), apkSigner) != 0)
|
||||
while (fgets(buffer, sizeof(buffer), apkSigner.get()) != nullptr)
|
||||
fprintf(stdout, "%s", buffer);
|
||||
|
||||
int errorCode = pclose(apkSigner);
|
||||
const int errorCode = pclose(apkSigner.release());
|
||||
if (errorCode != 0) {
|
||||
fprintf(stderr, "apksigner command failed.\n");
|
||||
if (!verbose)
|
||||
|
Loading…
x
Reference in New Issue
Block a user