diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2020-10-22 16:26:33 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2020-10-29 10:10:21 +0100 |
commit | 4e08651bacd8321f124610e4c5680811e1e9a0fa (patch) | |
tree | 70e1c80635dd88b71a54c31300d9310d081c564b /src/corelib/kernel/qcoreapplication.cpp | |
parent | 874eb19107e57774d6ec03f38578c584606eb5bc (diff) |
MinGW: Fix assert in QCoreApplication::arguments() when passing globs
We can't assume that the number of arguments we get from GetCommandLine
will match what we have from argc, as the former is not wildcard
expanded on MingGW.
mingw64 will ask __getmainargs to expand wildcards depending on
the mingw-specific variable _dowildcard. By default this is set
to 0 (false), but some mingw64-packagers (msys2, mingw-builds)
pass --enable-wildcard during build, changing this default. As
a result, the arguments we get through argc/__argc have already
been expanded. MinGW does not reflect this through GetCommandLine
though, like MSVC does, which triggered the assert.
Amends dff18b8e80609da91bf9e9134967dcf0d23eca9e.
Pick-to: 5.15
Fixes: QTBUG-67515
Task-number: QTBUG-84002
Change-Id: Ib87961c6901d2894b48ba0f5b9a3d6da2a595f24
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Simon Hausmann <hausmann@gmail.com>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src/corelib/kernel/qcoreapplication.cpp')
-rw-r--r-- | src/corelib/kernel/qcoreapplication.cpp | 63 |
1 files changed, 39 insertions, 24 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 29d31304be..44d8b8100a 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -387,10 +387,11 @@ static bool quitLockRefEnabled = true; #endif #if defined(Q_OS_WIN) -// Check whether the command line arguments match those passed to main() -// by comparing to the global __argv/__argc (MS extension). -// Deep comparison is required since argv/argc is rebuilt by WinMain for -// GUI apps or when using MinGW due to its globbing. +// Check whether the command line arguments passed to QCoreApplication +// match those passed into main(), to see if the user has modified them +// before passing them on to us. We do this by comparing to the global +// __argv/__argc (MS extension). Deep comparison is required since +// argv/argc is rebuilt by our WinMain entrypoint. static inline bool isArgvModified(int argc, char **argv) { if (__argc != argc || !__argv /* wmain() */) @@ -2422,32 +2423,46 @@ QStringList QCoreApplication::arguments() qWarning("QCoreApplication::arguments: Please instantiate the QApplication object first"); return list; } - const int ac = self->d_func()->argc; - char ** const av = self->d_func()->argv; - list.reserve(ac); - -#if defined(Q_OS_WIN) - // On Windows, it is possible to pass Unicode arguments on - // the command line. To restore those, we split the command line - // and filter out arguments that were deleted by derived application - // classes by index. - QString cmdline = QString::fromWCharArray(GetCommandLine()); const QCoreApplicationPrivate *d = self->d_func(); - if (d->origArgv) { - const QStringList allArguments = qWinCmdArgs(cmdline); - Q_ASSERT(allArguments.size() == d->origArgc); - for (int i = 0; i < d->origArgc; ++i) { - if (contains(ac, av, d->origArgv[i])) - list.append(allArguments.at(i)); + + const int argc = d->argc; + char ** const argv = d->argv; + list.reserve(argc); + +#if defined(Q_OS_WIN) + const bool argsModifiedByUser = d->origArgv == nullptr; + if (!argsModifiedByUser) { + // On Windows, it is possible to pass Unicode arguments on + // the command line, but we don't implement any of the wide + // entry-points (wmain/wWinMain), so get the arguments from + // the Windows API instead of using argv. Note that we only + // do this when argv were not modified by the user in main(). + QString cmdline = QString::fromWCharArray(GetCommandLine()); + QStringList commandLineArguments = qWinCmdArgs(cmdline); + + // Even if the user didn't modify argv before passing them + // on to QCoreApplication, derived QApplications might have. + // If that's the case argc will differ from origArgc. + if (argc != d->origArgc) { + // Note: On MingGW the arguments from GetCommandLine are + // not wildcard expanded (if wildcard expansion is enabled), + // as opposed to the arguments in argv. This means we can't + // compare commandLineArguments to argv/origArgc, but + // must remove elements by value, based on whether they + // were filtered out from argc. + for (int i = 0; i < d->origArgc; ++i) { + if (!contains(argc, argv, d->origArgv[i])) + commandLineArguments.removeAll(QString::fromLocal8Bit(d->origArgv[i])); + } } - return list; + + return commandLineArguments; } // Fall back to rebuilding from argv/argc when a modified argv was passed. #endif // defined(Q_OS_WIN) - for (int a = 0; a < ac; ++a) { - list << QString::fromLocal8Bit(av[a]); - } + for (int a = 0; a < argc; ++a) + list << QString::fromLocal8Bit(argv[a]); return list; } |