On Thu, Apr 5, 2018 at 3:08 AM Peter Zijlstra <pet...@infradead.org> wrote:
> On Wed, Apr 04, 2018 at 10:21:05PM +0000, James Y Knight wrote: > > But allowing random pointer arithmetic, and pointer arithmetic wraparound, > > is still different than asserting that an object _field access_ can > > overflow. Clang does not believe that can happen -- it assumes that an > > object will still be contiguous. And that's why the llist stuff used to be > > broken, before it was corrected to do simply do math on a uintptr_t (which > > is a nice and simple and sane fix!). > That 'fix' wasn't anything simple, I recently ran into that > member_address_is_nonnull() trainwreck and had to think real hard wtf it > was about. I agree the comment there could be clearer. You could replace it with something like this (apologies: this patch is likely going to be mangled by gmail's plaintext mode hard-wrapping it.) diff --git a/include/linux/llist.h b/include/linux/llist.h index 85abc2915e8d..04e972a0bbe8 100644 --- a/include/linux/llist.h +++ b/include/linux/llist.h @@ -99,12 +99,15 @@ static inline void init_llist_head(struct llist_head *list) * * This macro is conceptually the same as * &ptr->member != NULL - * but it works around the fact that compilers can decide that taking a member - * address is never a NULL pointer. - * - * Real objects that start at a high address and have a member at NULL are - * unlikely to exist, but such pointers may be returned e.g. by the - * container_of() macro. + * except that it uses addition on a uintptr_t instead of member + * access syntax. This avoids running into a compiler assumption that + * objects must be contiguous in memory, and therefore that member + * address lookup cannot wrap, and therefore that a field with a + * positive offset within an object can never be at address 0. + * + * Real objects which start at a high address and have a member at + * NULL do not exist, but such a pointer is the result of applying + * container_of() to NULL, which llist_for_each_entry does. */ #define member_address_is_nonnull(ptr, member) \ ((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0)