time: Avoid alignment gaps in __tzfile_read

By ordering the suballocations by decreasing alignment, alignment
gaps can be avoided.

Also use __glibc_unlikely for reading the transitions and type
indexes.  In the 8-byte case, two reads are now needed because the
transitions and type indexes are no longer adjacent.  The separate
call to __fread_unlocked does not matter from a performance point of
view because __tzfile_read is only invoked rarely.
This commit is contained in:
Florian Weimer 2019-02-04 10:01:29 +01:00
parent b8c7238167
commit 221baae001
2 changed files with 33 additions and 31 deletions

View File

@ -1,3 +1,8 @@
2019-02-04 Florian Weimer <fweimer@redhat.com>
* time/tzfile.c (__tzfile_read): Reorder suballocations to avoid
alignment gaps.
2019-02-03 Florian Weimer <fweimer@redhat.com> 2019-02-03 Florian Weimer <fweimer@redhat.com>
* time/tzfile.c (__tzfile_read): Use struct alloc_buffer and its * time/tzfile.c (__tzfile_read): Use struct alloc_buffer and its

View File

@ -246,25 +246,32 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
the following arrays: the following arrays:
__time64_t transitions[num_transitions]; __time64_t transitions[num_transitions];
struct leap leaps[num_leaps];
struct ttinfo types[num_types]; struct ttinfo types[num_types];
unsigned char type_idxs[num_types]; unsigned char type_idxs[num_types];
char zone_names[chars]; char zone_names[chars];
struct leap leaps[num_leaps];
char extra_array[extra]; // Stored into *pextras if requested.
char tzspec[tzspec_len]; char tzspec[tzspec_len];
char extra_array[extra]; // Stored into *pextras if requested.
The piece-wise allocations from buf below verify that no The piece-wise allocations from buf below verify that no
overflow/wraparound occurred in these computations. */ overflow/wraparound occurred in these computations.
The order of the suballocations is important for alignment
purposes. __time64_t outside a struct may require more alignment
then inside a struct on some architectures, so it must come
first. */
_Static_assert (__alignof (__time64_t) >= __alignof (struct leap),
"alignment of __time64_t");
_Static_assert (__alignof (struct leap) >= __alignof (struct ttinfo),
"alignment of struct leap");
struct alloc_buffer buf; struct alloc_buffer buf;
{ {
size_t total_size = num_transitions * (sizeof (__time64_t) + 1); size_t total_size = (num_transitions * sizeof (__time64_t)
total_size = ((total_size + __alignof__ (struct ttinfo) - 1) + num_leaps * sizeof (struct leap)
& ~(__alignof__ (struct ttinfo) - 1)); + num_types * sizeof (struct ttinfo)
total_size += num_types * sizeof (struct ttinfo) + chars; + num_transitions /* type_idxs */
total_size = ((total_size + __alignof__ (struct leap) - 1) + chars /* zone_names */
& ~(__alignof__ (struct leap) - 1)); + tzspec_len + extra);
total_size += num_leaps * sizeof (struct leap) + tzspec_len + extra;
transitions = malloc (total_size); transitions = malloc (total_size);
if (transitions == NULL) if (transitions == NULL)
goto lose; goto lose;
@ -274,35 +281,25 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
/* The address of the first allocation is already stored in the /* The address of the first allocation is already stored in the
pointer transitions. */ pointer transitions. */
(void) alloc_buffer_alloc_array (&buf, __time64_t, num_transitions); (void) alloc_buffer_alloc_array (&buf, __time64_t, num_transitions);
type_idxs = alloc_buffer_alloc_array (&buf, unsigned char, num_transitions);
types = alloc_buffer_alloc_array (&buf, struct ttinfo, num_types);
zone_names = alloc_buffer_alloc_array (&buf, char, chars);
leaps = alloc_buffer_alloc_array (&buf, struct leap, num_leaps); leaps = alloc_buffer_alloc_array (&buf, struct leap, num_leaps);
if (extra > 0) types = alloc_buffer_alloc_array (&buf, struct ttinfo, num_types);
*extrap = alloc_buffer_alloc_array (&buf, char, extra); type_idxs = alloc_buffer_alloc_array (&buf, unsigned char, num_transitions);
zone_names = alloc_buffer_alloc_array (&buf, char, chars);
if (trans_width == 8) if (trans_width == 8)
tzspec = alloc_buffer_alloc_array (&buf, char, tzspec_len); tzspec = alloc_buffer_alloc_array (&buf, char, tzspec_len);
else else
tzspec = NULL; tzspec = NULL;
if (extra > 0)
*extrap = alloc_buffer_alloc_array (&buf, char, extra);
if (alloc_buffer_has_failed (&buf)) if (alloc_buffer_has_failed (&buf))
goto lose; goto lose;
if (__builtin_expect (trans_width == 8, 1)) if (__glibc_unlikely (__fread_unlocked (transitions, trans_width,
{
if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1,
num_transitions, f) num_transitions, f)
!= num_transitions, 0)) != num_transitions)
|| __glibc_unlikely (__fread_unlocked (type_idxs, 1, num_transitions, f)
!= num_transitions))
goto lose; goto lose;
}
else
{
if (__builtin_expect (__fread_unlocked (transitions, 4,
num_transitions, f)
!= num_transitions, 0)
|| __builtin_expect (__fread_unlocked (type_idxs, 1, num_transitions,
f) != num_transitions, 0))
goto lose;
}
/* Check for bogus indices in the data file, so we can hereafter /* Check for bogus indices in the data file, so we can hereafter
safely use type_idxs[T] as indices into `types' and never crash. */ safely use type_idxs[T] as indices into `types' and never crash. */