Re: [PATCH v2 bpf-next 5/6] libbpf: fix BTF-to-C converter's padding logic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Dec 14, 2022 at 4:19 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote:
>
> On Mon, 2022-12-12 at 13:15 -0800, Andrii Nakryiko wrote:
> > Turns out that btf_dump API doesn't handle a bunch of tricky corner
> > cases, as reported by Per, and further discovered using his testing
> > Python script ([0]).
> >
> > This patch revamps btf_dump's padding logic significantly, making it
> > more correct and also avoiding unnecessary explicit padding, where
> > compiler would pad naturally. This overall topic turned out to be very
> > tricky and subtle, there are lots of subtle corner cases. The comments
> > in the code tries to give some clues, but comments themselves are
> > supposed to be paired with good understanding of C alignment and padding
> > rules. Plus some experimentation to figure out subtle things like
> > whether `long :0;` means that struct is now forced to be long-aligned
> > (no, it's not, turns out).
> >
> > Anyways, Per's script, while not completely correct in some known
> > situations, doesn't show any obvious cases where this logic breaks, so
> > this is a nice improvement over the previous state of this logic.
> >
> > Some selftests had to be adjusted to accommodate better use of natural
> > alignment rules, eliminating some unnecessary padding, or changing it to
> > `type: 0;` alignment markers.
> >
> > Note also that for when we are in between bitfields, we emit explicit
> > bit size, while otherwise we use `: 0`, this feels much more natural in
> > practice.
> >
> > Next patch will add few more test cases, found through randomized Per's
> > script.
> >
> >   [0] https://lore.kernel.org/bpf/85f83c333f5355c8ac026f835b18d15060725fcb.camel@xxxxxxxxxxxx/
> >
> > Reported-by: Per Sundström XP <per.xp.sundstrom@xxxxxxxxxxxx>
> > Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx>
> > ---
> >  tools/lib/bpf/btf_dump.c                      | 169 +++++++++++++-----
> >  .../bpf/progs/btf_dump_test_case_bitfields.c  |   2 +-
> >  .../bpf/progs/btf_dump_test_case_padding.c    |  58 ++++--
> >  3 files changed, 164 insertions(+), 65 deletions(-)
> >
> > diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
> > index 234e82334d56..d6fd93a57f11 100644
> > --- a/tools/lib/bpf/btf_dump.c
> > +++ b/tools/lib/bpf/btf_dump.c
> > @@ -830,6 +830,25 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
> >       }
> >  }
> >
> > +static int btf_natural_align_of(const struct btf *btf, __u32 id)
> > +{
> > +     const struct btf_type *t = btf__type_by_id(btf, id);
> > +     int i, align, vlen;
> > +     const struct btf_member *m;
> > +
> > +     if (!btf_is_composite(t))
> > +             return btf__align_of(btf, id);
> > +
> > +     align = 1;
> > +     m = btf_members(t);
> > +     vlen = btf_vlen(t);
> > +     for (i = 0; i < vlen; i++, m++) {
> > +             align = max(align, btf__align_of(btf, m->type));
> > +     }
> > +
> > +     return align;
> > +}
> > +
> >  static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
> >                                const struct btf_type *t)
> >  {
> > @@ -837,16 +856,16 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
> >       int align, i, bit_sz;
> >       __u16 vlen;
> >
> > -     align = btf__align_of(btf, id);
> > -     /* size of a non-packed struct has to be a multiple of its alignment*/
> > -     if (align && t->size % align)
> > +     align = btf_natural_align_of(btf, id);
> > +     /* size of a non-packed struct has to be a multiple of its alignment */
> > +     if (align && (t->size % align) != 0)
> >               return true;
> >
> >       m = btf_members(t);
> >       vlen = btf_vlen(t);
> >       /* all non-bitfield fields have to be naturally aligned */
> >       for (i = 0; i < vlen; i++, m++) {
> > -             align = btf__align_of(btf, m->type);
> > +             align = btf_natural_align_of(btf, m->type);
>
> Sorry, I'm late to the party...
>
> I think that this call to btf__align_of() should remain as is,
> otherwise the packed-ness of the m->type is ignored, which leads to
> the example below generating unnecessary packed annotation, which in
> turn leads to wrong result of sizeof() if asked.
> Reverting this hunk makes the test below work as expected and
> no other tests break.

Yep, I don't think I actually need btf_natural_align_of(), I'll just
adjust btf_is_struct_packed() instead. Thanks for another great catch!
I'll send a follow up fix.


>
> 02:02:44 tmp$ cat test.c
> #ifndef __BPF__
>
> #include <stddef.h>
> #include <stdio.h>
>
> #endif /* __BPF__ */
>
> struct a {
>   int x;
>   char y;
> }  __attribute__((packed));
>
> struct b {
>   short x;
>   struct a a;
> };
>
> #ifdef __BPF__
>
> int root(struct b *b) { return 7; }
>
> #else /* __BPF__ */
>
> struct b1 {
>   short x;
>   struct a a;
> } __attribute__((packed));
>
> int main() {
>   printf("sizeof(struct b ): %ld\n", sizeof(struct b));
>   printf("sizeof(struct b1): %ld\n", sizeof(struct b1));
> }
>
> #endif /* __BPF__ */
>
> 02:04:24 tmp$ clang test.c && ./a.out
> sizeof(struct b ): 8
> sizeof(struct b1): 7
>
> 02:04:30 tmp$ clang -target bpf -g -c test.c -o test.o && bpftool btf dump file ./test.o format c
> #ifndef __VMLINUX_H__
> #define __VMLINUX_H__
>
> #ifndef BPF_NO_PRESERVE_ACCESS_INDEX
> #pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)
> #endif
>
> struct a {
>         int x;
>         char y;
> } __attribute__((packed));
>
> struct b {
>         short x;
>         struct a a;
> } __attribute__((packed));
>
> #ifndef BPF_NO_PRESERVE_ACCESS_INDEX
> #pragma clang attribute pop
> #endif
>
> #endif /* __VMLINUX_H__ */
>
> >               bit_sz = btf_member_bitfield_size(t, i);
> >               if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
> >                       return true;

[...]




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux