RE: [PATCH v2] overflow: optimize struct_size() calculation

From: David Laight
Date: Wed Sep 11 2024 - 12:47:51 EST


...
> > [1] Both the '+' and '*' have extra code to detect overflow and return
> > a 'big' value that will cause kmalloc() to return NULL.
> > I've not looked at the generated code but it is likely to be horrid
> > (especially the check for multiply overflowing).
> > In this case there are enough constants that the alternative check:
> > if (count > (MAX_SIZE - sizeof (*s)) / sizeof (s->member))
> > size = MAX_SIZE;
> > else
> > size = sizeof (*s) + count * sizeof (s->member);
> > is fine and only has one conditional in it.
> > In some cases the compiler may already know that the count is small enough.
>
> Indeed. If count is small enough, the code isn't that horrid. If I
> take this example:
>
> size_t foo(u32 count)
> {
> return struct_size_t(struct s, fam, count);
> }
>
> I got this code:

What happens if the flex-array is larger than 1 byte - so a multiply is needed.
Probably worth testing something that isn't a power of 2.
Also check 32bit archs -godbolt can help.

David

>
> 0000000000000010 <foo>:
> 10: f3 0f 1e fa endbr64
> 14: 89 f8 mov %edi,%eax
> 16: 48 83 c0 10 add $0x10,%rax
> 1a: e9 00 00 00 00 jmp 1f <foo+0xf>

Add -d to objdump to get the relocation printed.
(I think this is a build where 'ret' isn't allowed :-)

David

>
> Here, no SIZE_MAX because the multiplication can not wraparound
> regardless of the value of count. It is only after changing the type
> of count to u64 that the compiler will emit a comparison:
>
> 0000000000000010 <foo>:
> 10: f3 0f 1e fa endbr64
> 14: 48 8d 47 10 lea 0x10(%rdi),%rax
> 18: 48 83 ff f0 cmp $0xfffffffffffffff0,%rdi
> 1c: 48 c7 c2 ff ff ff ff mov $0xffffffffffffffff,%rdx
> 23: 48 0f 43 c2 cmovae %rdx,%rax
> 27: e9 00 00 00 00 jmp 2c <foo+0x1c>
>
> For reference, this is the code after applying my patch, with count as a u32:
>
> 0000000000000010 <foo>:
> 10: f3 0f 1e fa endbr64
> 14: 89 f8 mov %edi,%eax
> 16: ba 10 00 00 00 mov $0x10,%edx
> 1b: 48 83 c0 0c add $0xc,%rax
> 1f: 48 39 d0 cmp %rdx,%rax
> 22: 48 0f 42 c2 cmovb %rdx,%rax
> 26: e9 00 00 00 00 jmp 2b <foo+0x1b>
>
> and with count as a u64:
>
> 0000000000000010 <foo>:
> 10: f3 0f 1e fa endbr64
> 14: 48 83 c7 0c add $0xc,%rdi
> 18: 72 11 jb 2b <foo+0x1b>
> 1a: b8 10 00 00 00 mov $0x10,%eax
> 1f: 48 39 c7 cmp %rax,%rdi
> 22: 48 0f 43 c7 cmovae %rdi,%rax
> 26: e9 00 00 00 00 jmp 2b <foo+0x1b>
> 2b: 48 83 c8 ff or $0xffffffffffffffff,%rax
> 2f: e9 00 00 00 00 jmp 34 <foo+0x24>
>
> Thank you for your comments!
>
>
> Yours sincerely,
> Vincent Mailhol

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)