Skip to content

incorrect bit-field access when preserve_access_index pushed #77720

Open
@zhaiyan920

Description

@zhaiyan920

Hi there,

I encountered incorrect bitfield access when tracing some linux kernel structure with BPF. Some attempt shows that generated code access bit fields inconsistent w/wo preserve_access_index. I managed to get a small reproducible case below:

//#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
//#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
//#endif

struct S {
        int x;
        char y;
        unsigned int a0:1;
        unsigned int a1:1;
        unsigned int a2:1;
        unsigned int a3:1;
        unsigned int a4:1;
        unsigned int a5:1;
        unsigned int a6:1;
        unsigned int a7:1;
        unsigned int b0:1;
        unsigned int b1:1;
        unsigned int b2:1;
        unsigned int b3:1;
        unsigned int b4:1;
        unsigned int b5:1;
        unsigned int b6:1;
        unsigned int b7:1;
};

//#ifndef BPF_NO_PRESERVE_ACCESS_INDEX
//#pragma clang attribute pop
//#endif

unsigned int func1(struct S *s) {
        return s->a0;
}

unsigned int func2(struct S *s) {
        return s->b0;
}

Without the attribute, this produces:

$ clang-16 test.c --target=bpf -c -O3 -g
$ llvm-objdump-16 -d test.o

test.o: file format elf64-bpf

Disassembly of section .text:

0000000000000000 <func1>:
       0:       71 10 05 00 00 00 00 00 r0 = *(u8 *)(r1 + 0x5)
       1:       57 00 00 00 01 00 00 00 r0 &= 0x1
       2:       95 00 00 00 00 00 00 00 exit

0000000000000018 <func2>:
       3:       71 10 06 00 00 00 00 00 r0 = *(u8 *)(r1 + 0x6)
       4:       57 00 00 00 01 00 00 00 r0 &= 0x1
       5:       95 00 00 00 00 00 00 00 exit

If I uncomment the attribute push lines, it generates:

$ clang-16 test.c --target=bpf -c -O3 -g
$ llvm-objdump-16 -d test.o

test.o: file format elf64-bpf

Disassembly of section .text:

0000000000000000 <func1>:
       0:       71 10 05 00 00 00 00 00 r0 = *(u8 *)(r1 + 0x5)
       1:       57 00 00 00 01 00 00 00 r0 &= 0x1
       2:       95 00 00 00 00 00 00 00 exit

0000000000000018 <func2>:
       3:       b7 02 00 00 06 00 00 00 r2 = 0x6
       4:       0f 21 00 00 00 00 00 00 r1 += r2
       5:       71 10 01 00 00 00 00 00 r0 = *(u8 *)(r1 + 0x1)
       6:       57 00 00 00 01 00 00 00 r0 &= 0x1
       7:       95 00 00 00 00 00 00 00 exit

Compiler info:

$ clang-16 --version
Debian clang version 16.0.6 (15~deb12u1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Pahole output:

struct S {
        int                        x;                    /*     0     4 */
        char                       y;                    /*     4     1 */

        /* Bitfield combined with previous fields */

        unsigned int               a0:1;                 /*     4: 8  4 */
        unsigned int               a1:1;                 /*     4: 9  4 */
        unsigned int               a2:1;                 /*     4:10  4 */
        unsigned int               a3:1;                 /*     4:11  4 */
        unsigned int               a4:1;                 /*     4:12  4 */
        unsigned int               a5:1;                 /*     4:13  4 */
        unsigned int               a6:1;                 /*     4:14  4 */
        unsigned int               a7:1;                 /*     4:15  4 */
        unsigned int               b0:1;                 /*     4:16  4 */
        unsigned int               b1:1;                 /*     4:17  4 */
        unsigned int               b2:1;                 /*     4:18  4 */
        unsigned int               b3:1;                 /*     4:19  4 */
        unsigned int               b4:1;                 /*     4:20  4 */
        unsigned int               b5:1;                 /*     4:21  4 */
        unsigned int               b6:1;                 /*     4:22  4 */
        unsigned int               b7:1;                 /*     4:23  4 */

        /* size: 8, cachelines: 1, members: 18 */
        /* bit_padding: 8 bits */
        /* last cacheline: 8 bytes */
};

I tried 17.0.2, which also shows similar result. An interesting thing is that if I remove the hole after y, everything becomes correct.

Seems a bug to me. Please let me know if there is anything else I can provide.

best
Yan

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions