[gnome-initial-setup/mcatanzaro/uselocale-take-2] Fix unsafe usage of setlocale()



commit 9ef38bacef35f8c431a49bd4dacc8850cedf41bb
Author: Michael Catanzaro <mcatanzaro gnome org>
Date:   Wed Feb 20 22:59:56 2019 -0600

    Fix unsafe usage of setlocale()
    
    setlocale() is MT-Unsafe so let's replace its usage with uselocale().
    Much safer! The locale is changed only for the main thread. Secondary
    threads will still get the global locale, but so what.
    
    cc-common-language will need to stop assuming it can get the current
    locale from the global locale rather than the thread-local locale, so
    have it get language from GisDriver instead of trying to get it out of
    accountsservice and then setlocale() if accountsservice doesn't have it.
    
    Fixes #53

 gnome-initial-setup/cc-common-language.c           | 30 ++++------
 gnome-initial-setup/cc-common-language.h           |  3 +-
 gnome-initial-setup/gis-driver.c                   | 66 +++++++++++++++-------
 gnome-initial-setup/gis-driver.h                   |  6 +-
 .../pages/language/gis-language-page.c             |  6 +-
 .../pages/language/gis-welcome-widget.c            | 13 +++--
 gnome-initial-setup/pages/region/gis-region-page.c | 12 ++--
 7 files changed, 75 insertions(+), 61 deletions(-)
---
diff --git a/gnome-initial-setup/cc-common-language.c b/gnome-initial-setup/cc-common-language.c
index 06b1769..cc3e8fe 100644
--- a/gnome-initial-setup/cc-common-language.c
+++ b/gnome-initial-setup/cc-common-language.c
@@ -36,6 +36,8 @@
 
 static char *get_lang_for_user_object_path (const char *path);
 
+static char *current_language;
+
 gboolean
 cc_common_language_has_font (const gchar *locale)
 {
@@ -97,23 +99,15 @@ cc_common_language_has_font (const gchar *locale)
 gchar *
 cc_common_language_get_current_language (void)
 {
-        gchar *language;
-        char *path;
-        const gchar *locale;
-
-       path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", getuid ());
-        language = get_lang_for_user_object_path (path);
-        g_free (path);
-        if (language != NULL && *language != '\0')
-                return gnome_normalize_locale (language);
-
-        locale = (const gchar *) setlocale (LC_MESSAGES, NULL);
-        if (locale)
-                language = gnome_normalize_locale (locale);
-        else
-                language = NULL;
-
-        return language;
+        g_assert (current_language != NULL);
+        return g_strdup (current_language);
+}
+
+void
+cc_common_language_set_current_language (const char *locale)
+{
+        g_clear_pointer (&current_language, g_free);
+        current_language = gnome_normalize_locale (locale);
 }
 
 static gboolean
@@ -249,7 +243,7 @@ insert_language (GHashTable *ht,
         key = g_strdup (lang);
 
         label_own_lang = gnome_get_language_from_locale (key, key);
-        label_current_lang = gnome_get_language_from_locale (key, NULL);
+        label_current_lang = gnome_get_language_from_locale (key, current_language);
         label_untranslated = gnome_get_language_from_locale (key, "C");
 
         /* We don't have a translation for the label in
diff --git a/gnome-initial-setup/cc-common-language.h b/gnome-initial-setup/cc-common-language.h
index 7f32cab..49ead3a 100644
--- a/gnome-initial-setup/cc-common-language.h
+++ b/gnome-initial-setup/cc-common-language.h
@@ -27,7 +27,8 @@
 
 G_BEGIN_DECLS
 
-gboolean cc_common_language_has_font                (const gchar  *locale);
+gboolean cc_common_language_has_font                (const gchar *locale);
+void     cc_common_language_set_current_language    (const gchar *locale);
 gchar   *cc_common_language_get_current_language    (void);
 GHashTable *cc_common_language_get_initial_languages   (void);
 
diff --git a/gnome-initial-setup/gis-driver.c b/gnome-initial-setup/gis-driver.c
index 989f47a..6c770d3 100644
--- a/gnome-initial-setup/gis-driver.c
+++ b/gnome-initial-setup/gis-driver.c
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 #include <locale.h>
 
+#include "cc-common-language.h"
 #include "gis-assistant.h"
 
 #define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ())
@@ -78,6 +79,8 @@ struct _GisDriverPrivate {
   GisDriverMode mode;
   UmAccountMode account_mode;
   gboolean small_screen;
+
+  locale_t locale;
 };
 typedef struct _GisDriverPrivate GisDriverPrivate;
 
@@ -95,6 +98,12 @@ gis_driver_finalize (GObject *object)
 
   g_clear_object (&priv->user_account);
 
+  if (priv->locale != (locale_t) 0)
+    {
+      uselocale (LC_GLOBAL_LOCALE);
+      freelocale (priv->locale);
+    }
+
   G_OBJECT_CLASS (gis_driver_parent_class)->finalize (object);
 }
 
@@ -140,12 +149,46 @@ gis_driver_get_assistant (GisDriver *driver)
   return priv->assistant;
 }
 
+static void
+gis_driver_real_locale_changed (GisDriver *driver)
+{
+  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+  GtkTextDirection direction;
+
+  direction = gtk_get_locale_direction ();
+  gtk_widget_set_default_direction (direction);
+
+  rebuild_pages (driver);
+  gis_assistant_locale_changed (priv->assistant);
+}
+
+static void
+gis_driver_locale_changed (GisDriver *driver)
+{
+  g_signal_emit (G_OBJECT (driver), signals[LOCALE_CHANGED], 0);
+}
+
 void
-gis_driver_set_user_language (GisDriver *driver, const gchar *lang_id)
+gis_driver_set_user_language (GisDriver *driver, const gchar *lang_id, gboolean update_locale)
 {
   GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
+
   g_free (priv->lang_id);
   priv->lang_id = g_strdup (lang_id);
+
+  cc_common_language_set_current_language (lang_id);
+
+  if (update_locale)
+    {
+      locale_t locale = newlocale (LC_MESSAGES_MASK, lang_id, (locale_t) 0);
+      uselocale (locale);
+
+      if (priv->locale != (locale_t) 0 && priv->locale != LC_GLOBAL_LOCALE)
+        freelocale (priv->locale);
+      priv->locale = locale;
+
+      gis_driver_locale_changed (driver);
+    }
 }
 
 const gchar *
@@ -221,25 +264,6 @@ gis_driver_hide_window (GisDriver *driver)
   gtk_widget_hide (GTK_WIDGET (priv->main_window));
 }
 
-static void
-gis_driver_real_locale_changed (GisDriver *driver)
-{
-  GisDriverPrivate *priv = gis_driver_get_instance_private (driver);
-  GtkTextDirection direction;
-
-  direction = gtk_get_locale_direction ();
-  gtk_widget_set_default_direction (direction);
-
-  rebuild_pages (driver);
-  gis_assistant_locale_changed (priv->assistant);
-}
-
-void
-gis_driver_locale_changed (GisDriver *driver)
-{
-  g_signal_emit (G_OBJECT (driver), signals[LOCALE_CHANGED], 0);
-}
-
 GisDriverMode
 gis_driver_get_mode (GisDriver *driver)
 {
@@ -447,7 +471,7 @@ gis_driver_startup (GApplication *app)
 
   gtk_widget_show (GTK_WIDGET (priv->assistant));
 
-  gis_driver_set_user_language (driver, setlocale (LC_MESSAGES, NULL));
+  gis_driver_set_user_language (driver, setlocale (LC_MESSAGES, NULL), FALSE);
 
   prepare_main_window (driver);
   rebuild_pages (driver);
diff --git a/gnome-initial-setup/gis-driver.h b/gnome-initial-setup/gis-driver.h
index 9eb408e..32f5355 100644
--- a/gnome-initial-setup/gis-driver.h
+++ b/gnome-initial-setup/gis-driver.h
@@ -65,7 +65,6 @@ typedef enum {
 GType gis_driver_get_type (void);
 
 GisAssistant *gis_driver_get_assistant (GisDriver *driver);
-void gis_driver_locale_changed (GisDriver *driver);
 
 void gis_driver_set_user_permissions (GisDriver   *driver,
                                       ActUser     *user,
@@ -81,9 +80,10 @@ void gis_driver_set_account_mode (GisDriver     *driver,
 UmAccountMode gis_driver_get_account_mode (GisDriver *driver);
 
 void gis_driver_set_user_language (GisDriver   *driver,
-                                   const gchar *lang_id);
+                                   const gchar *lang_id,
+                                   gboolean     update_locale);
 
-const gchar *gis_driver_get_user_language (GisDriver   *driver);
+const gchar *gis_driver_get_user_language (GisDriver *driver);
 
 void gis_driver_set_username (GisDriver   *driver,
                               const gchar *username);
diff --git a/gnome-initial-setup/pages/language/gis-language-page.c 
b/gnome-initial-setup/pages/language/gis-language-page.c
index a4afe44..386ee4e 100644
--- a/gnome-initial-setup/pages/language/gis-language-page.c
+++ b/gnome-initial-setup/pages/language/gis-language-page.c
@@ -123,7 +123,7 @@ language_changed (CcLanguageChooser  *chooser,
   priv->new_locale_id = cc_language_chooser_get_language (chooser);
   driver = GIS_PAGE (page)->driver;
 
-  setlocale (LC_MESSAGES, priv->new_locale_id);
+  gis_driver_set_user_language (driver, priv->new_locale_id, TRUE);
   gtk_widget_set_default_direction (gtk_get_locale_direction ());
 
   if (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER) {
@@ -153,12 +153,8 @@ language_changed (CcLanguageChooser  *chooser,
                       G_CALLBACK (user_loaded),
                       g_strdup (priv->new_locale_id));
 
-  gis_driver_set_user_language (driver, priv->new_locale_id);
-
   gis_welcome_widget_show_locale (GIS_WELCOME_WIDGET (priv->welcome_widget),
                                   priv->new_locale_id);
-
-  gis_driver_locale_changed (driver);
 }
 
 static void
diff --git a/gnome-initial-setup/pages/language/gis-welcome-widget.c 
b/gnome-initial-setup/pages/language/gis-welcome-widget.c
index 87b28d4..37b000f 100644
--- a/gnome-initial-setup/pages/language/gis-welcome-widget.c
+++ b/gnome-initial-setup/pages/language/gis-welcome-widget.c
@@ -111,18 +111,21 @@ gis_welcome_widget_unmap (GtkWidget *widget)
 static char *
 welcome (const char *locale_id)
 {
-  char *current_locale_id;
+  locale_t locale;
+  locale_t old_locale;
   char *welcome;
 
-  current_locale_id = g_strdup (setlocale (LC_MESSAGES, NULL));
-  setlocale (LC_MESSAGES, locale_id);
+  locale = newlocale (LC_MESSAGES_MASK, locale_id, (locale_t) 0);
+  old_locale = uselocale (locale);
+
   /* Translators: This is meant to be a warm, engaging welcome message,
    * like greeting somebody at the door. If the exclamation mark is not
    * suitable for this in your language you may replace it.
    */
   welcome = _("Welcome!");
-  setlocale (LC_MESSAGES, current_locale_id);
-  g_free (current_locale_id);
+
+  uselocale (old_locale);
+  freelocale (locale);
 
   return welcome;
 }
diff --git a/gnome-initial-setup/pages/region/gis-region-page.c 
b/gnome-initial-setup/pages/region/gis-region-page.c
index 5a31b9c..1e65356 100644
--- a/gnome-initial-setup/pages/region/gis-region-page.c
+++ b/gnome-initial-setup/pages/region/gis-region-page.c
@@ -118,10 +118,9 @@ region_changed (CcRegionChooser  *chooser,
     return;
 
   priv->new_locale_id = cc_region_chooser_get_locale (chooser);
-  driver = GIS_PAGE (page)->driver;
 
-  setlocale (LC_MESSAGES, priv->new_locale_id);
-  gis_driver_locale_changed (driver);
+  driver = GIS_PAGE (page)->driver;
+  gis_driver_set_user_language (driver, priv->new_locale_id, FALSE);
 
   if (gis_driver_get_mode (driver) == GIS_DRIVER_MODE_NEW_USER) {
       if (g_permission_get_allowed (priv->permission)) {
@@ -143,8 +142,6 @@ region_changed (CcRegionChooser  *chooser,
                       "notify::is-loaded",
                       G_CALLBACK (user_loaded),
                       g_strdup (priv->new_locale_id));
-
-  gis_driver_set_user_language (driver, priv->new_locale_id);
 }
 
 static void
@@ -221,16 +218,15 @@ static void
 gis_region_page_locale_changed (GisPage *page)
 {
   GisRegionPagePrivate *priv = gis_region_page_get_instance_private (GIS_REGION_PAGE (page));
-  char *locale;
+  const char *locale;
 
   gis_page_set_title (page, _("Region"));
 
-  locale = g_strdup (setlocale (LC_MESSAGES, NULL));
+  locale = gis_driver_get_user_language (page->driver);
 
   priv->updating = TRUE;
   cc_region_chooser_set_locale (CC_REGION_CHOOSER (priv->region_chooser), locale);
   priv->updating = FALSE;
-  g_free (locale);
 
   if (cc_region_chooser_get_n_regions (CC_REGION_CHOOSER (priv->region_chooser)) > 1)
     gtk_widget_show (GTK_WIDGET (page));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]