XCode 26.6 Apple LLVM 21.0 bug in O1

#include <stdio.h>

void test50() { unsigned int b = 0x7d40d133; unsigned int m = 0x22e5bbf; unsigned int r = 64; b += (((m) << ((int)(r))) | ((m) >> (32 - (int)(r)))); // expect b = 0x7f6f2cf2, however in opt bigger than O1, b = 0x819d88b1 printf("%#x\n", b); }

int main() { test50(); return 0; }

Compiling with -O0 and -O1 produces different results. There appears to be a compiler optimization bug that is triggered when r % 32 == 0,This feature works correctly in Xcode 26.0.

Answered by DTS Engineer in 899529022

First up, it’s hard to read your post because of the formatting. See tip 5 in Quinn’s Top Ten DevForums Tips for some advice on that front.

Here’s a copy of what I think your program should look like:

#include <stdio.h>

static void test50(void) {
    unsigned int b = 0x7d40d133;
    unsigned int m = 0x22e5bbf;
    unsigned int r = 64;
    b += (((m) << ((int)(r))) | ((m) >> (32 - (int)(r))));
    // expect b = 0x7f6f2cf2, however in opt bigger than O1, b = 0x819d88b1
    printf("%#x\n", b);
}

int main(int argc, char ** argv) {
    #pragma unused(argc)
    #pragma unused(argv)
    test50();
    return 0;
}

Note that I’ve made some tweaks so that it compiles without warnings in my standard Xcode setup. Please check my code to make sure I didn’t mess up something important.

Looking at this code I’m concerned about r being 64. In C, the shift factor must be less than the bit width. Anything else is undefined behaviour. And seeing as m is an unsigned int, which is 32 bits, shifting by 64 bits seems like an issue.

To confirm this I put your code into an Xcode test project and turned on UBSan (Product > Scheme > Edit Scheme > Run > Diagnostics > Undefined Behavior Sanitizer [1]). And when I ran that, I saw this output:

…/main.c:7:16: runtime error: shift exponent 64 is too large for 32-bit type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior …/main.c:7:16 
…/main.c:7:38: runtime error: shift exponent -32 is negative
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior …/main.c:7:38 
0x7f6f2cf2

If your program relies on undefined behaviour than the compiler is allowed to produce different output based on any criteria, including the optimisation level.

When programming in a C-based language it’s important to test with all the sanitisers. C is full of nasty traps like this.

This is one of the many reasons I avoid programming in C whenever I can. Life is so much better in ‘modern’ languages. Obviously, as an Apple person, I use Swift, but there are lots of nice modern language out there that can help you avoid problems like this.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Two American spellings in one phrase. Yuck!

First up, it’s hard to read your post because of the formatting. See tip 5 in Quinn’s Top Ten DevForums Tips for some advice on that front.

Here’s a copy of what I think your program should look like:

#include <stdio.h>

static void test50(void) {
    unsigned int b = 0x7d40d133;
    unsigned int m = 0x22e5bbf;
    unsigned int r = 64;
    b += (((m) << ((int)(r))) | ((m) >> (32 - (int)(r))));
    // expect b = 0x7f6f2cf2, however in opt bigger than O1, b = 0x819d88b1
    printf("%#x\n", b);
}

int main(int argc, char ** argv) {
    #pragma unused(argc)
    #pragma unused(argv)
    test50();
    return 0;
}

Note that I’ve made some tweaks so that it compiles without warnings in my standard Xcode setup. Please check my code to make sure I didn’t mess up something important.

Looking at this code I’m concerned about r being 64. In C, the shift factor must be less than the bit width. Anything else is undefined behaviour. And seeing as m is an unsigned int, which is 32 bits, shifting by 64 bits seems like an issue.

To confirm this I put your code into an Xcode test project and turned on UBSan (Product > Scheme > Edit Scheme > Run > Diagnostics > Undefined Behavior Sanitizer [1]). And when I ran that, I saw this output:

…/main.c:7:16: runtime error: shift exponent 64 is too large for 32-bit type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior …/main.c:7:16 
…/main.c:7:38: runtime error: shift exponent -32 is negative
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior …/main.c:7:38 
0x7f6f2cf2

If your program relies on undefined behaviour than the compiler is allowed to produce different output based on any criteria, including the optimisation level.

When programming in a C-based language it’s important to test with all the sanitisers. C is full of nasty traps like this.

This is one of the many reasons I avoid programming in C whenever I can. Life is so much better in ‘modern’ languages. Obviously, as an Apple person, I use Swift, but there are lots of nice modern language out there that can help you avoid problems like this.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Two American spellings in one phrase. Yuck!

XCode 26.6 Apple LLVM 21.0 bug in O1
 
 
Q