On Wed, Jan 24, 2024 at 12:29:51AM +0000, Qing Zhao wrote:
> This is the 4th version of the patch.

Thanks very much for this!

I tripped over an unexpected behavioral change that the Linux kernel
depends on:

__builtin_types_compatible_p() no longer treats an array marked with
counted_by as different from that array's decayed pointer. Specifically,
the kernel uses these macros:


/*
 * Force a compilation error if condition is true, but also produce a
 * result (of value 0 and type int), so the expression can be used
 * e.g. in a structure initializer (or where-ever else comma expressions
 * aren't permitted).
 */
#define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))

#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

/* &a[0] degrades to a pointer: a different type from an array */
#define __must_be_array(a)   BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))


This gets used in various places to make sure we're dealing with an
array for a macro:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))


So this builds:

struct untracked {
        int size;
        int array[];
} *a;

__must_be_array(a->array)
        => 0 (as expected)
__builtin_types_compatible_p(typeof(a->array), typeof(&(a->array)[0]))
        => 0 (as expected, array vs decayed array pointer)


But if counted_by is added, we get a build failure:

struct tracked {
        int size;
        int array[] __counted_by(size);
} *b;

__must_be_array(b->array)
        => build failure (not expected)
__builtin_types_compatible_p(typeof(b->array), typeof(&(b->array)[0]))
        => 1 (not expected, both pointers?)




-- 
Kees Cook

Reply via email to