Simplify and relax UTF-8 locale override machinery for Darwin

There's no need to try the various permutations of the language
and region specific locales, as they all point back to the same
CTYPE in /usr/share/locale/UTF-8/LC_CTYPE

In addition, processes started from launchd come with an empty
locale environment (LC_ALL/LC_*/LANG), and hence will default
to the "C"/POSIX locale, even after picking up the environment.
This primarily applies to applications launched from Finder,
but also affects processes launched as background services.
And since a child process will inherit its parent's environment
the empty locale environment is propagated when running apps
from IDEs such as Qt Creator or Xcode, or commands in an SSH
login session (as sshd is a background service), unless the
environment has been explicitly set up by the shell (Zsh).

Since neither of these situations is the result of user
misconfiguration, it makes little sense to spit our a
warning.

We however still warn if we detect that the character
encoding has changed from the default "C" encoding, or
if the encoding is "C", but we detect that the user has
modified any of the relevant locale environment variables,
as this indicates either a change in the system default
behavior, or that the user has explicitly requested a
"C" locale, which is wrong.

Done-with: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Fixes: QTBUG-111443
Pick-to: 6.5.0 6.5 6.4 6.2
Change-Id: I6fd14d1f8adddc2914d6ff4d3b5ad34a3871ef82
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Edward Welbourne 2023-02-27 16:40:59 +01:00
parent fff9395c28
commit ac6c7aa12f

View File

@ -625,7 +625,20 @@ void QCoreApplicationPrivate::initLocale()
const char *charEncoding = nl_langinfo(CODESET);
if (Q_UNLIKELY(qstricmp(charEncoding, "UTF-8") != 0 && qstricmp(charEncoding, "utf8") != 0)) {
const QByteArray oldLocale = setlocale(LC_ALL, nullptr);
QByteArray newLocale = setlocale(LC_CTYPE, nullptr);
QByteArray newLocale;
bool warnOnOverride = true;
# if defined(Q_OS_DARWIN)
// Don't warn unless the char encoding has been changed from the
// default "C" encoding, or the user touched any of the locale
// environment variables to force the "C" char encoding.
warnOnOverride = qstrcmp(setlocale(LC_CTYPE, nullptr), "C") != 0
|| getenv("LC_ALL") || getenv("LC_CTYPE") || getenv("LANG");
// No need to try language or region specific CTYPEs, as they
// all point back to the same generic UTF-8 CTYPE.
newLocale = setlocale(LC_CTYPE, "UTF-8");
# else
newLocale = setlocale(LC_CTYPE, nullptr);
if (qsizetype dot = newLocale.indexOf('.'); dot != -1)
newLocale.truncate(dot); // remove encoding, if any
if (qsizetype at = newLocale.indexOf('@'); at != -1)
@ -634,14 +647,11 @@ void QCoreApplicationPrivate::initLocale()
newLocale = setlocale(LC_CTYPE, newLocale);
// If that locale doesn't exist, try some fallbacks:
# if defined(Q_OS_DARWIN)
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "UTF-8");
# endif
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.UTF-8");
if (newLocale.isEmpty())
newLocale = setlocale(LC_CTYPE, "C.utf8");
# endif
if (newLocale.isEmpty()) {
// Failed to set a UTF-8 locale.
@ -649,7 +659,7 @@ void QCoreApplicationPrivate::initLocale()
"Qt depends on a UTF-8 locale, but has failed to switch to one.\n"
"If this causes problems, reconfigure your locale. See the locale(1) manual\n"
"for more information.", oldLocale.constData(), charEncoding);
} else {
} else if (warnOnOverride) {
// Let the user know we over-rode their configuration.
qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
"Qt depends on a UTF-8 locale, and has switched to \"%s\" instead.\n"