aboutsummaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2022-05-23 10:08:18 +0200
committerFlorian Weimer <fweimer@redhat.com>2022-05-23 11:06:31 +0200
commit7ee41feba6b834d9e17e634bfbf222c4d8dd1a4f (patch)
treecae31634fe857b963791bf3697bdae20312acc2e /time
parentbbebe83a2874cd25934046d908824dfc11711a2b (diff)
downloadglibc-7ee41feba6b834d9e17e634bfbf222c4d8dd1a4f.zip
glibc-7ee41feba6b834d9e17e634bfbf222c4d8dd1a4f.tar.gz
glibc-7ee41feba6b834d9e17e634bfbf222c4d8dd1a4f.tar.bz2
locale: Remove private union from struct __locale_data
This avoids an alias violation later. This commit also fixes an incorrect double-checked locking idiom in _nl_init_era_entries. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'time')
-rw-r--r--time/alt_digit.c47
-rw-r--r--time/era.c48
-rw-r--r--time/lc-time-cleanup.c4
3 files changed, 45 insertions, 54 deletions
diff --git a/time/alt_digit.c b/time/alt_digit.c
index 7ed9b6b..331cb39 100644
--- a/time/alt_digit.c
+++ b/time/alt_digit.c
@@ -30,19 +30,18 @@ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
#define CURRENT_WSTR(item) \
((wchar_t *) current->values[_NL_ITEM_INDEX (item)].wstr)
-static void
+static struct lc_time_data *
_nl_init_alt_digit (struct __locale_data *current)
{
- struct lc_time_data *data;
+ struct lc_time_data *data = current->private;
- if (current->private.time == NULL)
+ if (data == NULL)
{
- current->private.time = malloc (sizeof *current->private.time);
- if (current->private.time == NULL)
- return;
- memset (current->private.time, 0, sizeof *current->private.time);
+ data = calloc (sizeof *data, 1);
+ if (data == NULL)
+ return NULL;
+ current->private = data;
}
- data = current->private.time;
if (! data->alt_digits_initialized)
{
@@ -65,6 +64,7 @@ _nl_init_alt_digit (struct __locale_data *current)
}
}
+ return data;
}
const char *
@@ -77,13 +77,11 @@ _nl_get_alt_digit (unsigned int number, struct __locale_data *current)
__libc_rwlock_wrlock (__libc_setlocale_lock);
- if (current->private.time == NULL
- || ! current->private.time->alt_digits_initialized)
- _nl_init_alt_digit (current);
+ struct lc_time_data *data = _nl_init_alt_digit (current);
- result = ((current->private.time != NULL
- && current->private.time->alt_digits != NULL)
- ? current->private.time->alt_digits[number]
+ result = ((data != NULL
+ && data->alt_digits != NULL)
+ ? data->alt_digits[number]
: NULL);
__libc_rwlock_unlock (__libc_setlocale_lock);
@@ -96,21 +94,20 @@ const wchar_t *
_nl_get_walt_digit (unsigned int number, struct __locale_data *current)
{
const wchar_t *result = NULL;
- struct lc_time_data *data;
if (number >= 100 || CURRENT_WSTR (_NL_WALT_DIGITS)[0] == L'\0')
return NULL;
__libc_rwlock_wrlock (__libc_setlocale_lock);
- if (current->private.time == NULL)
+ struct lc_time_data *data = current->private;
+ if (data == NULL)
{
- current->private.time = malloc (sizeof *current->private.time);
- if (current->private.time == NULL)
+ data = calloc (sizeof *data, 1);
+ if (data == NULL)
goto out;
- memset (current->private.time, 0, sizeof *current->private.time);
+ current->private = data;
}
- data = current->private.time;
if (! data->walt_digits_initialized)
{
@@ -156,12 +153,8 @@ _nl_parse_alt_digit (const char **strp, struct __locale_data *current)
__libc_rwlock_wrlock (__libc_setlocale_lock);
- if (current->private.time == NULL
- || ! current->private.time->alt_digits_initialized)
- _nl_init_alt_digit (current);
-
- if (current->private.time != NULL
- && current->private.time->alt_digits != NULL)
+ struct lc_time_data *data = _nl_init_alt_digit (current);
+ if (data != NULL && data->alt_digits != NULL)
/* Matching is not unambiguous. The alternative digits could be like
I, II, III, ... and the first one is a substring of the second
and third. Therefore we must keep on searching until we found
@@ -169,7 +162,7 @@ _nl_parse_alt_digit (const char **strp, struct __locale_data *current)
the standard. */
for (cnt = 0; cnt < 100; ++cnt)
{
- const char *const dig = current->private.time->alt_digits[cnt];
+ const char *const dig = data->alt_digits[cnt];
size_t len = strlen (dig);
if (len > maxlen && strncmp (dig, str, len) == 0)
diff --git a/time/era.c b/time/era.c
index d4b538c..7f18071 100644
--- a/time/era.c
+++ b/time/era.c
@@ -35,7 +35,7 @@ __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
/* Look up the era information in CURRENT's locale strings and
cache it in CURRENT->private. */
-static void
+static struct lc_time_data *
_nl_init_era_entries (struct __locale_data *current)
{
size_t cnt;
@@ -43,18 +43,22 @@ _nl_init_era_entries (struct __locale_data *current)
/* Avoid touching CURRENT if there is no data at all, for _nl_C_LC_TIME. */
if (CURRENT_WORD (_NL_TIME_ERA_NUM_ENTRIES) == 0)
- return;
+ return NULL;
+
+ data = current->private;
+ if (data != NULL && atomic_load_acquire (&data->era_initialized))
+ return data;
__libc_rwlock_wrlock (__libc_setlocale_lock);
- if (current->private.time == NULL)
+ data = current->private;
+ if (data == NULL)
{
- current->private.time = malloc (sizeof *current->private.time);
- if (current->private.time == NULL)
+ data = calloc (sizeof *data, 1);
+ if (data == NULL)
goto out;
- memset (current->private.time, 0, sizeof *current->private.time);
+ current->private = data;
}
- data = current->private.time;
if (! data->era_initialized)
{
@@ -130,33 +134,30 @@ _nl_init_era_entries (struct __locale_data *current)
}
}
- data->era_initialized = 1;
+ atomic_store_release (&data->era_initialized, 1);
}
out:
__libc_rwlock_unlock (__libc_setlocale_lock);
+ return data;
}
struct era_entry *
_nl_get_era_entry (const struct tm *tp, struct __locale_data *current)
{
- if (current->private.time == NULL || !current->private.time->era_initialized)
- _nl_init_era_entries (current);
+ struct lc_time_data *data = _nl_init_era_entries (current);
- if (current->private.time != NULL)
+ if (data != NULL)
{
/* Now compare date with the available eras. */
const int32_t tdate[3] = { tp->tm_year, tp->tm_mon, tp->tm_mday };
size_t cnt;
- for (cnt = 0; cnt < current->private.time->num_eras; ++cnt)
- if ((ERA_DATE_CMP (current->private.time->eras[cnt].start_date, tdate)
- && ERA_DATE_CMP (tdate,
- current->private.time->eras[cnt].stop_date))
- || (ERA_DATE_CMP (current->private.time->eras[cnt].stop_date,
- tdate)
- && ERA_DATE_CMP (tdate,
- current->private.time->eras[cnt].start_date)))
- return &current->private.time->eras[cnt];
+ for (cnt = 0; cnt < data->num_eras; ++cnt)
+ if ((ERA_DATE_CMP (data->eras[cnt].start_date, tdate)
+ && ERA_DATE_CMP (tdate, data->eras[cnt].stop_date))
+ || (ERA_DATE_CMP (data->eras[cnt].stop_date, tdate)
+ && ERA_DATE_CMP (tdate, data->eras[cnt].start_date)))
+ return &data->eras[cnt];
}
return NULL;
@@ -166,9 +167,6 @@ _nl_get_era_entry (const struct tm *tp, struct __locale_data *current)
struct era_entry *
_nl_select_era_entry (int cnt, struct __locale_data *current)
{
- if (current->private.time == NULL || !current->private.time->era_initialized)
- _nl_init_era_entries (current);
-
- return (current->private.time == NULL
- ? NULL : &current->private.time->eras[cnt]);
+ struct lc_time_data *data = _nl_init_era_entries (current);
+ return data == NULL ? NULL : &data->eras[cnt];
}
diff --git a/time/lc-time-cleanup.c b/time/lc-time-cleanup.c
index f844e04..bcf6d2f 100644
--- a/time/lc-time-cleanup.c
+++ b/time/lc-time-cleanup.c
@@ -22,10 +22,10 @@
void
_nl_cleanup_time (struct __locale_data *locale)
{
- struct lc_time_data *const data = locale->private.time;
+ struct lc_time_data *const data = locale->private;
if (data != NULL)
{
- locale->private.time = NULL;
+ locale->private = NULL;
free (data->eras);
free (data->alt_digits);