Hi,
I noticed that some parts of OpenBSD use awkward techniques to detect
undefined behavior in arithmetic operations, for example:
> static size_t
> poolBytesToAllocateFor(int blockSize) {
> /* Unprotected math would be:
> ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
> **
> ** Detect overflow, avoiding _signed_ overflow undefined behavior
> ** For a + b * c we check b * c in isolation first, so that addition of
a
> ** on top has no chance of making us accept a small non-negative number
> */
> const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */
>
> if (blockSize <= 0)
> return 0;
>
> if (blockSize > (int)(INT_MAX / stretch))
> return 0;
>
> {
> const int stretchedBlockSize = blockSize * (int)stretch;
> const int bytesToAllocate
> = (int)(offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
> if (bytesToAllocate < 0)
> return 0;
>
> return (size_t)bytesToAllocate;
> }
> }
The snippet was taken from lib/libexpat/lib/xmlparse.c
This does not fully protect the code because bytesToAllocate might
overflow in the unsigned addition resulting in bytesToAllocate > 0. Note
that unsigned overflow is not undefined behavior but leads to unexpected
results.
C23 solves this problem using <stdckdint.h> [1] which transforms the
above function into:
> static size_t
> poolBytesToAllocateFor(int blockSize) {
> size_t add, mul;
> if (ckd_mul(&mul, blockSize, sizeof(XML_Char)))
> return 0;
> if (ckd_add(&add, mul, offsetof(BLOCK, s)))
> return 0;
> return add;
> }
Is it worth bringing this functionality in OpenBSD? As a starting point
I was thinking that we can make use of __builtin_add_overflow et al.
when compiling with Clang. GCC is trickier to solve as the builtins were
implemented from version 5.
Best Regards,
Lucian Popescu
[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2681.pdf