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.
This commit is contained in:
Michael Catanzaro 2019-02-20 23:42:38 -06:00 committed by Michael Catanzaro
parent cb75ca664b
commit a22da99aaf
4 changed files with 85 additions and 34 deletions

View file

@ -18,6 +18,7 @@
*
*/
#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <glib.h>
@ -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;
}

View file

@ -22,6 +22,7 @@
#include <config.h>
#include "cc-format-chooser.h"
#include <errno.h>
#include <locale.h>
#include <langinfo.h>
#include <string.h>
@ -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
}

View file

@ -19,6 +19,7 @@
*/
#include <config.h>
#include <errno.h>
#include <locale.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
@ -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 ();

View file

@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <locale.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n.h>
@ -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);
}
}