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:
parent
b8c7238167
commit
221baae001
@ -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
|
||||||
|
@ -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. */
|
||||||
|
Loading…
Reference in New Issue
Block a user