Clang incorrectly optimizing out for conditional in Linux

I filed an issue with the Kernel (here 195235 – llist.h llist_for_each_entry/llist_for_each_entry_safe have undefined behavior) to capture this issue. Hopefully this is something that they will fix! I'll note that my suggested answer assumes they want the behavior to remain the same, though I'm not sure that is what they MEANT.

-Erich

Hi,

I am trying to get the Linux kernel to compile and boot using clang.
The code compiles fine, but the kernel does not boot. It looks like
the following macro in mm/vmalloc.c (line 650) is optimizing out the
exit condition on the for loop:

#define llist_for_each_entry(pos, node, member) \
    for ((pos) = llist_entry((node), typeof(*(pos)), member); \
         &(pos)->member != NULL;

This comparison is tautologically true because it'd be UB to construct the address if pos were null, and true otherwise.

Jon

         \

         (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))

snip

As I recall, this particular kernel idiom is one that caused GCC to add an extra flag to restrict their optimisations, because rewriting Linux in C was harder than hacking the compiler to support Linux-flavoured almost-C, so I wouldn’t hold out much hope for Linux fixing the code - this is far from the only place that this idiom occurs and has been the cause of at least one security vulnerability.

David

Well Blarg, that is disappointing. In THIS case, I at least have a hope, the original implementer and I share an organization, so hopefully he'll be willing to fix it out of internal good will :slight_smile:

In the meanwhile, were you able to talk with the implementer about your proposed change, Erich? If you and the implementer agree on your fix, maybe I can add it to my source and get going on my work.

I was not, I sent him an email, but he and I are in different hemispheres, so we likely are going to have a few days lag.