From d6131d2157a1871d754cdb9a6e231615c3702f53 Mon Sep 17 00:00:00 2001 From: Richard Pospesel Date: Wed, 15 Nov 2017 10:48:38 -0800 Subject: [PATCH] Bug 23016: "Print to File" does not create the expected file in non-English locales The Problem: During firefox and Web Content process startup, ::OverrideDefaultLocaleIfNeeded() is called which will conditionally ::setlocale() to "C.UTF-8" or "C" based off of the javascript.use_us_english_locale preference (to prevent fingerprinting based on how dates and what-not are formatted). Sometime after this call in the Web Content process the locale is set to the system's locale which effectively stomps over the work done by the ::OverrideDefaultLocaleIfNeeded() call. As a result, the firefox process and the Web Content process are configured to use different locales; firefox uses "C.UTF-8" while Web Content uses "" (system default). On Linux, the "Print to File" printer is a default GTK printer whose name is localized based off of the process's locale. The GTK print dialog is hosted in the firefox process and therefore the printer name will be 'Print to File.' This process sends this name over to the Web Content process, which iterates over the list of printers and finds one whose name matches. However, as the Web Content process's locale is set to system, its printer names will be localized and in the language of the system, so no printer with the name 'Print to File' will be found, and printing fails. This is why disabling javascript.use_us_english_locale fixes the issue. It also explains why disabling multi-process mode via the browser.tabs.remote.autostart.2 preference fixes the issue; one process means the printer-name is never used as a selector and also means no mismatched locale can happen. The Solution: The fix for this issue is to first check the javascript.use_us_english_locale preference each place in code where setlocale occurs, particularly in the nsLocaleService object which is the particular code path which overrides setlocale in the Web Content process. --- intl/locale/nsLocaleService.cpp | 72 +++++++++++++++++++++---------- xpcom/build/XPCOMInit.cpp | 14 ++++-- xpcom/io/nsNativeCharsetUtils.cpp | 14 +++++- 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/intl/locale/nsLocaleService.cpp b/intl/locale/nsLocaleService.cpp index 6d45ec9afa2aa..e89ff32346cd7 100644 --- a/intl/locale/nsLocaleService.cpp +++ b/intl/locale/nsLocaleService.cpp @@ -12,6 +12,7 @@ #include "nsTArray.h" #include "nsString.h" #include "mozilla/UniquePtr.h" +#include "mozilla/Preferences.h" #include @@ -93,12 +94,20 @@ protected: // nsLocaleService::nsLocaleService(void) { + // conditionally use us english locale when initialization locale objects + const auto use_us_english_locale = + mozilla::Preferences::GetBool("javascript.use_us_english_locale", false); + #ifdef XP_WIN nsAutoString xpLocale; + // 1033 is default english us locale LCID + // https://msdn.microsoft.com/en-us/library/ms912047(v=winembedded.10).aspx + const LCID en_US_lcid = 1033; + // // get the system LCID // - LCID win_lcid = GetSystemDefaultLCID(); + LCID win_lcid = use_us_english_locale ? en_US_lcid : GetSystemDefaultLCID(); NS_ENSURE_TRUE_VOID(win_lcid); nsWin32Locale::GetXPLocale(win_lcid, xpLocale); nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale)); @@ -107,7 +116,7 @@ nsLocaleService::nsLocaleService(void) // // get the application LCID // - win_lcid = GetUserDefaultLCID(); + win_lcid = use_us_english_locale ? en_US_lcid : GetUserDefaultLCID(); NS_ENSURE_TRUE_VOID(win_lcid); nsWin32Locale::GetXPLocale(win_lcid, xpLocale); rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale)); @@ -118,7 +127,7 @@ nsLocaleService::nsLocaleService(void) NS_ENSURE_TRUE_VOID(resultLocale); // Get system configuration - const char* lang = getenv("LANG"); + const char* lang = use_us_english_locale ? "en-US" : getenv("LANG"); nsAutoString xpLocale, platformLocale; nsAutoString category, category_platform; @@ -127,7 +136,19 @@ nsLocaleService::nsLocaleService(void) for( i = 0; i < LocaleListLength; i++ ) { nsresult result; // setlocale( , "") evaluates LC_* and LANG - char* lc_temp = setlocale(posix_locale_category[i], ""); + const auto current_posix_locale_category = posix_locale_category[i]; + const char* lc_temp = nullptr; + + if (use_us_english_locale) { + lc_temp = setlocale(current_posix_locale_category, "C.UTF-8"); + if (lc_temp == nullptr) { + lc_temp = setlocale(current_posix_locale_category, "C"); + } + } + else { + lc_temp = setlocale(current_posix_locale_category, ""); + } + CopyASCIItoUTF16(LocaleList[i], category); category_platform = category; category_platform.AppendLiteral("##PLATFORM"); @@ -163,30 +184,37 @@ nsLocaleService::nsLocaleService(void) #endif // XP_UNIX #ifdef XP_MACOSX - // Get string representation of user's current locale - CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent(); - CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef); - ::CFRetain(userLocaleStr); - - AutoTArray buffer; - int size = ::CFStringGetLength(userLocaleStr); - buffer.SetLength(size + 1); - CFRange range = ::CFRangeMake(0, size); - ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements()); - buffer[size] = 0; - - // Convert the locale string to the format that Mozilla expects - nsAutoString xpLocale(reinterpret_cast(buffer.Elements())); - xpLocale.ReplaceChar('_', '-'); + nsAutoString xpLocale; + + if (use_us_english_locale) { + xpLocale = NS_LITERAL_STRING("en-US").get(); + } + else { + // Get string representation of user's current locale + CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent(); + CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef); + ::CFRetain(userLocaleStr); + + AutoTArray buffer; + int size = ::CFStringGetLength(userLocaleStr); + buffer.SetLength(size + 1); + CFRange range = ::CFRangeMake(0, size); + ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements()); + buffer[size] = 0; + + // Convert the locale string to the format that Mozilla expects + xpLocale = reinterpret_cast(buffer.Elements()); + xpLocale.ReplaceChar('_', '-'); + + ::CFRelease(userLocaleStr); + ::CFRelease(userLocaleRef); + } nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale)); if (NS_SUCCEEDED(rv)) { mApplicationLocale = mSystemLocale; } - ::CFRelease(userLocaleStr); - ::CFRelease(userLocaleRef); - NS_ASSERTION(mApplicationLocale, "Failed to create locale objects"); #endif // XP_MACOSX } diff --git a/xpcom/build/XPCOMInit.cpp b/xpcom/build/XPCOMInit.cpp index c72ea48d77c88..4fe9c93de2eca 100644 --- a/xpcom/build/XPCOMInit.cpp +++ b/xpcom/build/XPCOMInit.cpp @@ -11,6 +11,7 @@ #include "mozilla/Poison.h" #include "mozilla/SharedThreadPool.h" #include "mozilla/XPCOM.h" +#include "mozilla/Preferences.h" #include "nsXULAppAPI.h" #include "nsXPCOMPrivate.h" @@ -571,11 +572,18 @@ NS_InitXPCOM2(nsIServiceManager** aResult, } #ifndef ANDROID + // If the locale hasn't already been setup by our embedder, - // get us out of the "C" locale and into the system - if (strcmp(setlocale(LC_ALL, nullptr), "C") == 0) { - setlocale(LC_ALL, ""); + // get us out of the "C" locale and into the system, + // but only do so if we aren't force using english locale + if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) { + setlocale(LC_ALL, "C.UTF-8") || setlocale(LC_ALL, "C"); + } else { + if (strcmp(setlocale(LC_ALL, nullptr), "C") == 0) { + setlocale(LC_ALL, ""); + } } + #endif #if defined(XP_UNIX) diff --git a/xpcom/io/nsNativeCharsetUtils.cpp b/xpcom/io/nsNativeCharsetUtils.cpp index e53307af56285..f81c1179256bf 100644 --- a/xpcom/io/nsNativeCharsetUtils.cpp +++ b/xpcom/io/nsNativeCharsetUtils.cpp @@ -48,6 +48,7 @@ NS_ShutdownNativeCharsetUtils() #include // mbtowc, wctomb #include // setlocale #include "mozilla/Mutex.h" +#include "mozilla/Preferences.h" #include "nscore.h" #include "nsAString.h" #include "nsReadableUtils.h" @@ -316,7 +317,12 @@ nsNativeCharsetConverter::LazyInit() // NS_StartupNativeCharsetUtils, assume we are called early enough that // we are the first to care about the locale's charset. if (!gLock) { - setlocale(LC_CTYPE, ""); + + if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) { + setlocale(LC_CTYPE, "C.UTF-8") || setlocale(LC_CTYPE, "C"); + } else { + setlocale(LC_CTYPE, ""); + } } const char* blank_list[] = { "", nullptr }; const char** native_charset_list = blank_list; @@ -884,7 +890,11 @@ NS_StartupNativeCharsetUtils() // XXX we assume that we are called early enough that we should // always be the first to care about the locale's charset. // - setlocale(LC_CTYPE, ""); + if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) { + setlocale(LC_CTYPE, "C.UTF-8") || setlocale(LC_CTYPE, "C"); + } else { + setlocale(LC_CTYPE, ""); + } nsNativeCharsetConverter::GlobalInit(); } -- GitLab