From a22da99aaf9853518b1dcf491c633f8d71856947 Mon Sep 17 00:00:00 2001 From: Michael Catanzaro Date: Wed, 20 Feb 2019 23:42:38 -0600 Subject: [PATCH] Replace unsafe setlocale() use with uselocale() setlocale() is not threadsafe except when used only to query the locale without changing it. Let's use uselocale() instead, which changes the locale only on the calling thread. Much better. --- panels/datetime/date-endian.c | 17 +++++-- panels/region/cc-format-chooser.c | 68 ++++++++++++++++++++-------- panels/region/cc-region-panel.c | 17 +++++-- panels/user-accounts/cc-user-panel.c | 17 ++++--- 4 files changed, 85 insertions(+), 34 deletions(-) diff --git a/panels/datetime/date-endian.c b/panels/datetime/date-endian.c index 34f1d3893..435a423af 100644 --- a/panels/datetime/date-endian.c +++ b/panels/datetime/date-endian.c @@ -18,6 +18,7 @@ * */ +#include #include #include #include @@ -149,12 +150,22 @@ DateEndianess date_endian_get_for_lang (const char *lang, gboolean verbose) { - const char *old_lang; + locale_t locale; + locale_t old_locale; DateEndianess endian; - old_lang = setlocale (LC_TIME, lang); + locale = newlocale (LC_TIME_MASK, lang, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", lang, g_strerror (errno)); + else + old_locale = uselocale (locale); + endian = date_endian_get_default (verbose); - setlocale (LC_TIME, old_lang); + + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } return endian; } diff --git a/panels/region/cc-format-chooser.c b/panels/region/cc-format-chooser.c index 56ba6e16d..cd6d9994e 100644 --- a/panels/region/cc-format-chooser.c +++ b/panels/region/cc-format-chooser.c @@ -22,6 +22,7 @@ #include #include "cc-format-chooser.h" +#include #include #include #include @@ -66,48 +67,66 @@ display_date (GtkWidget *label, GDateTime *dt, const gchar *format) static void update_format_examples (CcFormatChooser *chooser) { - g_autofree gchar *time_locale = NULL; - g_autofree gchar *numeric_locale = NULL; - g_autofree gchar *monetary_locale = NULL; - g_autofree gchar *measurement_locale = NULL; - g_autofree gchar *paper_locale = NULL; + locale_t locale; + locale_t old_locale; g_autoptr(GDateTime) dt = NULL; g_autofree gchar *s = NULL; const gchar *fmt; g_autoptr(GtkPaperSize) paper = NULL; - time_locale = g_strdup (setlocale (LC_TIME, NULL)); - setlocale (LC_TIME, chooser->region); + locale = newlocale (LC_TIME_MASK, chooser->region, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", chooser->region, g_strerror (errno)); + else + old_locale = uselocale (locale); dt = g_date_time_new_now_local (); display_date (chooser->date_format_label, dt, "%x"); display_date (chooser->time_format_label, dt, "%X"); display_date (chooser->date_time_format_label, dt, "%c"); - setlocale (LC_TIME, time_locale); + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } - numeric_locale = g_strdup (setlocale (LC_NUMERIC, NULL)); - setlocale (LC_NUMERIC, chooser->region); + locale = newlocale (LC_NUMERIC_MASK, chooser->region, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", chooser->region, g_strerror (errno)); + else + old_locale = uselocale (locale); s = g_strdup_printf ("%'.2f", 123456789.00); gtk_label_set_text (GTK_LABEL (chooser->number_format_label), s); - setlocale (LC_NUMERIC, numeric_locale); + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } #if 0 - monetary_locale = g_strdup (setlocale (LC_MONETARY, NULL)); - setlocale (LC_MONETARY, chooser->region); + locale = newlocale (LC_MONETARY_MASK, chooser->region, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", chooser->region, g_strerror (errno)); + else + old_locale = uselocale (locale); num_info = localeconv (); if (num_info != NULL) gtk_label_set_text (GTK_LABEL (chooser->currency_format_label), num_info->currency_symbol); - setlocale (LC_MONETARY, monetary_locale); + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } #endif #ifdef LC_MEASUREMENT - measurement_locale = g_strdup (setlocale (LC_MEASUREMENT, NULL)); - setlocale (LC_MEASUREMENT, chooser->region); + locale = newlocale (LC_MEASUREMENT_MASK, chooser->region, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", chooser->region, g_strerror (errno)); + else + old_locale = uselocale (locale); fmt = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT); if (fmt && *fmt == 2) @@ -115,17 +134,26 @@ update_format_examples (CcFormatChooser *chooser) else gtk_label_set_text (GTK_LABEL (chooser->measurement_format_label), C_("measurement format", "Metric")); - setlocale (LC_MEASUREMENT, measurement_locale); + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } #endif #ifdef LC_PAPER - paper_locale = g_strdup (setlocale (LC_PAPER, NULL)); - setlocale (LC_PAPER, chooser->region); + locale = newlocale (LC_PAPER_MASK, chooser->region, (locale_t) 0); + if (locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", chooser->region, g_strerror (errno)); + else + old_locale = uselocale (locale); paper = gtk_paper_size_new (gtk_paper_size_get_default ()); gtk_label_set_text (GTK_LABEL (chooser->paper_format_label), gtk_paper_size_get_display_name (paper)); - setlocale (LC_PAPER, paper_locale); + if (locale != (locale_t) 0) { + uselocale (old_locale); + freelocale (locale); + } #endif } diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c index e968e1379..39b1f9d7b 100644 --- a/panels/region/cc-region-panel.c +++ b/panels/region/cc-region-panel.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -228,20 +229,26 @@ set_restart_notification_visible (CcRegionPanel *self, const gchar *locale, gboolean visible) { - g_autofree gchar *current_locale = NULL; + locale_t new_locale; + locale_t current_locale; g_autoptr(GFile) file = NULL; g_autoptr(GFileOutputStream) output_stream = NULL; g_autoptr(GError) error = NULL; if (locale) { - current_locale = g_strdup (setlocale (LC_MESSAGES, NULL)); - setlocale (LC_MESSAGES, locale); + new_locale = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0); + if (new_locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", locale, g_strerror (errno)); + else + current_locale = uselocale (new_locale); } gtk_revealer_set_reveal_child (self->restart_revealer, visible); - if (locale) - setlocale (LC_MESSAGES, current_locale); + if (locale && new_locale != (locale_t) 0) { + uselocale (current_locale); + freelocale (new_locale); + } file = get_needs_restart_file (); diff --git a/panels/user-accounts/cc-user-panel.c b/panels/user-accounts/cc-user-panel.c index 23abf48a1..086a0f2ce 100644 --- a/panels/user-accounts/cc-user-panel.c +++ b/panels/user-accounts/cc-user-panel.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -954,18 +955,22 @@ restart_now (CcUserPanel *self) static void show_restart_notification (CcUserPanel *self, const gchar *locale) { - gchar *current_locale; + locale_t current_locale; + locale_t new_locale; if (locale) { - current_locale = g_strdup (setlocale (LC_MESSAGES, NULL)); - setlocale (LC_MESSAGES, locale); + new_locale = newlocale (LC_MESSAGES_MASK, locale, (locale_t) 0); + if (new_locale == (locale_t) 0) + g_warning ("Failed to create locale %s: %s", locale, g_strerror (errno)); + else + current_locale = uselocale (new_locale); } gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); - if (locale) { - setlocale (LC_MESSAGES, current_locale); - g_free (current_locale); + if (locale && new_locale != (locale_t) 0) { + uselocale (current_locale); + freelocale (new_locale); } }