llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.06k stars 11.98k forks source link

[Clang][CodeGen] __bdos off by 4 #111009

Open Cydox opened 1 month ago

Cydox commented 1 month ago

Under certain circumstances __bdos can be off by 4 bytes compared to gcc.

Seen in the linux kernel: https://lore.kernel.org/linux-kernel/3D0816D1-0807-4D37-8D5F-3C55CA910FAA@linux.dev/

Reproducer from Thorsten Blum (also here: https://godbolt.org/z/vvK9PE1Yq):

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int counter;
} atomic_t;

typedef struct refcount_struct {
    atomic_t refs;
} refcount_t;

struct callback_head {
    struct callback_head *next;
    void (*func)(struct callback_head *head);
} __attribute__((aligned(sizeof(void *))));
#define rcu_head callback_head

typedef struct {
    uid_t val;
} kuid_t;

typedef struct {
    gid_t val;
} kgid_t;

struct posix_acl_entry {
    short e_tag;
    unsigned short e_perm;
    union {
        kuid_t e_uid;
        kgid_t e_gid;
    };
};

struct posix_acl {
    refcount_t a_refcount;
    struct rcu_head a_rcu;
    unsigned int a_count;
    struct posix_acl_entry a_entries[] __attribute__((counted_by(a_count)));
};

int main() {
    unsigned int count = 1;
    struct posix_acl *acl;

    acl = malloc(sizeof(struct posix_acl) +
                 sizeof(struct posix_acl_entry) * count);
    acl->a_count = count;

    printf("%zu", __builtin_dynamic_object_size(acl, 0));
    return 0;
}
Cydox commented 1 month ago

I do have a fix for this I'll submit shortly.

llvmbot commented 1 month ago

@llvm/issue-subscribers-clang-codegen

Author: Jan Hendrik Farr (Cydox)

Under certain circumstances __bdos can be off by 4 bytes compared to gcc. Seen in the linux kernel: https://lore.kernel.org/linux-kernel/3D0816D1-0807-4D37-8D5F-3C55CA910FAA@linux.dev/ Reproducer from Thorsten Blum (also here: https://godbolt.org/z/vvK9PE1Yq): ```C #include <stdio.h> #include <stdlib.h> typedef struct { int counter; } atomic_t; typedef struct refcount_struct { atomic_t refs; } refcount_t; struct callback_head { struct callback_head *next; void (*func)(struct callback_head *head); } __attribute__((aligned(sizeof(void *)))); #define rcu_head callback_head typedef struct { uid_t val; } kuid_t; typedef struct { gid_t val; } kgid_t; struct posix_acl_entry { short e_tag; unsigned short e_perm; union { kuid_t e_uid; kgid_t e_gid; }; }; struct posix_acl { refcount_t a_refcount; struct rcu_head a_rcu; unsigned int a_count; struct posix_acl_entry a_entries[] __attribute__((counted_by(a_count))); }; int main() { unsigned int count = 1; struct posix_acl *acl; acl = malloc(sizeof(struct posix_acl) + sizeof(struct posix_acl_entry) * count); acl->a_count = count; printf("%zu", __builtin_dynamic_object_size(acl, 0)); return 0; } ```
nickdesaulniers commented 1 month ago

cc @nathanchance @kees @bwendling

Cydox commented 1 month ago

Fix is at: https://github.com/Cydox/llvm-project/tree/fix-bdos-offby4 Just adding an additional test based on the reproducer now (and waiting for a full recompile as I just rebased on top of main)