mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
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>
This commit is contained in:
parent
bbebe83a28
commit
7ee41feba6
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_ADDRESS attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
13,
|
||||
|
@ -25,7 +25,7 @@ const struct __locale_data _nl_C_LC_COLLATE attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
19,
|
||||
|
@ -542,7 +542,7 @@ const struct __locale_data _nl_C_LC_CTYPE attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
1, /* Enable transliteration by default. */
|
||||
NR_FIXED + NR_CLASSES + NR_MAPS,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_IDENTIFICATION attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
16,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_MEASUREMENT attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
2,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_MESSAGES attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
5,
|
||||
|
@ -27,7 +27,7 @@ const struct __locale_data _nl_C_LC_MONETARY attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
46,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_NAME attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
7,
|
||||
|
@ -23,7 +23,7 @@ const struct __locale_data _nl_C_LC_NUMERIC attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
6,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_PAPER attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
3,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_TELEPHONE attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
5,
|
||||
|
@ -26,7 +26,7 @@ const struct __locale_data _nl_C_LC_TIME attribute_hidden =
|
||||
{
|
||||
_nl_C_name,
|
||||
NULL, 0, 0, /* no file mapped */
|
||||
{ NULL, }, /* no cached data */
|
||||
NULL, /* No cached data. */
|
||||
UNDELETABLE,
|
||||
0,
|
||||
159,
|
||||
|
@ -59,13 +59,13 @@ struct __locale_data
|
||||
} alloc;
|
||||
|
||||
/* This provides a slot for category-specific code to cache data
|
||||
computed about this locale. This is deallocated at the start of
|
||||
_nl_unload_locale. */
|
||||
union
|
||||
{
|
||||
struct lc_time_data *time;
|
||||
const struct gconv_fcts *ctype;
|
||||
} private;
|
||||
computed about this locale. Type of the data pointed to:
|
||||
|
||||
LC_CTYPE struct gconv_fcts (get_gconv_fcts, __wcsmbs_load_conv)
|
||||
LC_TIME struct lc_time_data (_nl_init_alt_digit, _nl_init_era_entries)
|
||||
|
||||
This data deallocated at the start of _nl_unload_locale. */
|
||||
void *private;
|
||||
|
||||
unsigned int usage_count; /* Counter for users. */
|
||||
|
||||
|
@ -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)
|
||||
|
48
time/era.c
48
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 ¤t->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 : ¤t->private.time->eras[cnt]);
|
||||
struct lc_time_data *data = _nl_init_era_entries (current);
|
||||
return data == NULL ? NULL : &data->eras[cnt];
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -155,7 +155,7 @@ __wcsmbs_load_conv (struct __locale_data *new_category)
|
||||
|
||||
/* We should repeat the test since while we waited some other thread
|
||||
might have run this function. */
|
||||
if (__glibc_likely (new_category->private.ctype == NULL))
|
||||
if (__glibc_likely (new_category->private == NULL))
|
||||
{
|
||||
/* We must find the real functions. */
|
||||
const char *charset_name;
|
||||
@ -199,10 +199,10 @@ __wcsmbs_load_conv (struct __locale_data *new_category)
|
||||
free (new_fcts);
|
||||
|
||||
failed:
|
||||
new_category->private.ctype = &__wcsmbs_gconv_fcts_c;
|
||||
new_category->private = (void *) &__wcsmbs_gconv_fcts_c;
|
||||
}
|
||||
else
|
||||
new_category->private.ctype = new_fcts;
|
||||
new_category->private = new_fcts;
|
||||
}
|
||||
|
||||
__libc_rwlock_unlock (__libc_setlocale_lock);
|
||||
@ -263,10 +263,10 @@ __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
|
||||
void
|
||||
_nl_cleanup_ctype (struct __locale_data *locale)
|
||||
{
|
||||
const struct gconv_fcts *const data = locale->private.ctype;
|
||||
const struct gconv_fcts *const data = locale->private;
|
||||
if (data != NULL && data != &__wcsmbs_gconv_fcts_c)
|
||||
{
|
||||
locale->private.ctype = NULL;
|
||||
locale->private = NULL;
|
||||
|
||||
/* Free the old conversions. */
|
||||
__gconv_close_transform (data->tomb, data->tomb_nsteps);
|
||||
|
@ -66,13 +66,15 @@ extern const struct __locale_data _nl_C_LC_CTYPE attribute_hidden;
|
||||
static inline const struct gconv_fcts *
|
||||
get_gconv_fcts (struct __locale_data *data)
|
||||
{
|
||||
if (__glibc_unlikely (data->private.ctype == NULL))
|
||||
struct gconv_fcts *private = data->private;
|
||||
if (private == NULL)
|
||||
{
|
||||
if (__glibc_unlikely (data == &_nl_C_LC_CTYPE))
|
||||
if (data == &_nl_C_LC_CTYPE)
|
||||
return &__wcsmbs_gconv_fcts_c;
|
||||
__wcsmbs_load_conv (data);
|
||||
private = data->private;
|
||||
}
|
||||
return data->private.ctype;
|
||||
return private;
|
||||
}
|
||||
|
||||
#endif /* wcsmbsload.h */
|
||||
|
Loading…
Reference in New Issue
Block a user