Skip to content

UBSan should not warn on integer overflow with downcast or bitwise-AND mask #133497

Open
@Explorer09

Description

@Explorer09

Test code

#include <stdint.h>
#include <stdio.h>

static inline unsigned int popCount8(uint8_t x) {
   // Formula borrowed from https://github.com/llvm/llvm-project/issues/79823
   uint32_t n = (uint32_t)(x * 0x08040201U);
   n = ((((n >> 3) & 0x11111111U) * 0x11111111U) & 0xF0000000U) >> 28;
   return n;
}

int main(void) {
   volatile uint8_t x;
   x = 0xFF;
   // Expected output: 8
   printf("%u\n", popCount8(x));
   return 0;
}

Compile with: clang -fsanitize=integer -o test test.c
Then run with ./test

Actual behavior

test1.c:6:30: runtime error: unsigned integer overflow: 255 * 134480385 cannot be represented in type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior test1.c:6:30 in 
test1.c:7:35: runtime error: unsigned integer overflow: 286331153 * 286331153 cannot be represented in type 'unsigned int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior test1.c:7:44 in 

Expected behavior

No errors and no warnings.

The compiler and UndefinedBehaviorSanitizer should not warn about both overflow cases as I have made downcasts and bitwise-AND masks to tell that the "overflows" are intentional.

  • (uint32_t)(x * 0x08040201U)
  • ((x * 0x11111111U) & 0xF0000000U)

While I can workaround the bug by adding a upcast like this...

  • (uint32_t)((uint64_t)x * 0x08040201U)
  • (((uint64_t)x * 0x11111111U) & 0xF0000000U)

... I would rather like conciseness and not needing such casts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions