Re: llist code relies on undefined behaviour, upsets llvm/clang
flat view
From: Peter Zijlstra <peterz@infradead.org>
Date: 2017-01-16 16:25:37
Also in:
lkml
On Mon, Jan 16, 2017 at 02:34:43PM +0000, David Laight wrote:
From: Anton Blanchardquoted
Sent: 15 January 2017 21:36 I was debugging a hang on a ppc64le kernel built with clang, and it looks to be undefined behaviour with pointer wrapping in the llist code. A test case is below. llist_for_each_entry() does container_of() on a NULL pointer, which wraps our pointer negative, then adds the same offset back in and expects to get back to NULL. Unfortunately clang decides that this can never be NULL and optimises it into an infinite loop....quoted
#define llist_for_each_entry(pos, node, member) \ for ((pos) = llist_entry((node), typeof(*(pos)), member); \ &(pos)->member != NULL; \ (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))Maybe the above could be rewritten as (untested): for ((pos) = NULL; (!(pos) ? (node) : ((pos)->member.next) || (pos) = 0) && \ (((pos) = !(pos) ? llist_entry((node), typeof(*(pos)), member) \ : llist_entry((pos)->member.next, typeof(*(pos)), member)),1); ) Provided the compiler assumes that the loop body is never executed with 'pos == 0' it should generate the same code.
That's far uglier code and to what point? The compiler should simply not assume silly things.