49 lines
1.8 KiB
Diff
49 lines
1.8 KiB
Diff
Upstream thread:
|
|
|
|
https://sourceware.org/ml/libc-alpha/2017-07/msg00487.html
|
|
|
|
Relevant analysis:
|
|
|
|
_int_malloc is inlined into tcache_init, and the allocation size is
|
|
constant-propagated into it. GCC does not realize that global_max_fast
|
|
is limited MAX_FAST_SIZE, so it compiles the true branch of the if
|
|
statement:
|
|
|
|
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
|
|
{
|
|
idx = fastbin_index (nb);
|
|
mfastbinptr *fb = &fastbin (av, idx);
|
|
mchunkptr pp = *fb;
|
|
REMOVE_FB (fb, victim, pp);
|
|
if (victim != 0)
|
|
|
|
under the assumption that nb == sizeof (tcache_perthread_struct) == 576,
|
|
which is larger than MAX_FAST_SIZE, so the fastbin access is compiled
|
|
into an OOB array subscript. GCC does not proceed to eliminate this
|
|
code, even though it has undefined behavior and will never execute in
|
|
practice.
|
|
|
|
This is neither a glibc bug nor a GCC bug. It merely reflects the
|
|
difficulty of producing good warnings from optimizers. But it does
|
|
break the build in rawhide due to -Werror.
|
|
|
|
Index: b/malloc/malloc.c
|
|
===================================================================
|
|
--- a/malloc/malloc.c
|
|
+++ b/malloc/malloc.c
|
|
@@ -3566,6 +3566,14 @@ _int_malloc (mstate av, size_t bytes)
|
|
while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \
|
|
!= victim); \
|
|
|
|
+ /* _int_malloc can be inlined to a caller with a constant size
|
|
+ argument. In this case, the compiler will see an out-of-bounds
|
|
+ array access in the true branch of the if statement below if it
|
|
+ cannot show that global_max_fast cannot be larger than
|
|
+ MAX_FAST_SIZE. The assert shows the compiler that this cannot
|
|
+ happen. */
|
|
+ assert (!__builtin_constant_p (nb) || global_max_fast <= MAX_FAST_SIZE);
|
|
+
|
|
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
|
|
{
|
|
idx = fastbin_index (nb);
|