This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RM57L843: RM57L843: ARM-CGT-CLANG: Anonymous bit-field padding not zero-initialized in designated initializer with runtime value

Part Number: RM57L843

When a struct with anonymous bit-field padding is initialized via a designated initializer containing a runtime value, the compiler at -O0 fails to zero-initialize the anonymous padding bits. The generated code reads the uninitialized stack byte and only modifies the named bit-field, leaving the anonymous padding with whatever garbage was on the stack.
 
The bug does not occur when:
- The initializer value is a compile-time constant (e.g., true)
- The padding bit-field is given a name (e.g., unsigned int reserved : 7)
- Optimization is -O1 or higher (the compiler takes a different code generation path)
 
The issue is reproduced when compiling the following program using TI Arm Clang Compiler 4.0.3.LTS (tiarmclang 18.1.8):
#include <stdbool.h>
#include <stdint.h>

typedef struct {
    bool field_a : 1;       // bit 0
    unsigned int : 7;       // bits 1-7 (anonymous padding)
} __attribute__((packed)) packed_t;

typedef union {
    packed_t s;
    uint8_t  byte;
} test_t;

/* At -O0, result.byte may contain garbage in bits 1-7.
 * At -O1 or higher, result.byte is correct.
 * Naming the padding (e.g., "unsigned int reserved : 7")
 * also produces correct results at -O0.
 */
test_t make(bool val) {
    test_t result = { .s.field_a = val };
    return result;
}


Compile commands:
tiarmclang -mcpu=cortex-r5 -mthumb -O0 -std=c17 -S anonimous_members_bug.c -o anonimous_members_bug_O0.s
tiarmclang -mcpu=cortex-r5 -mthumb -O1 -std=c17 -S anonimous_members_bug.c -o anonimous_members_bug_O1.s
 
The generated assembly for make at -O0 reads the result byte from the stack before it has ever been written to, then only modifies bit 0:

 

make:
    sub   sp, #4
    strb.w r0, [sp, #2]       @ save parameter
    ldrb.w r0, [sp, #2]       @ reload parameter
    and   r1, r0, #1          @ extract bit 0
    ldrb.w r0, [sp, #3]       @ BUG: read UNINITIALIZED byte from stack
    and   r0, r0, #254        @ clear only bit 0, preserve bits 1-7 (garbage)
    add   r0, r1              @ set bit 0
    strb.w r0, [sp, #3]       @ write back (bits 1-7 still garbage)
    ldrb.w r0, [sp, #3]       @ return value contains garbage in bits 1-7
    add   sp, #4
    bx    lr

 

At -O1, the function compiles to just bx lr (the optimizer eliminates the issue entirely).