Introduce `OverflowBehaviorType` (OBT), a new type attribute in Clang that provides developers with fine-grained control over the overflow behavior of integer types. This feature allows for a more nuanced approach to integer safety, achieving better granularity than global compiler flags like `-fwrapv` and `-ftrapv`. Type specifiers are also available as keywords `__ob_wrap` and `__ob_trap`. These can be applied to integer types (both signed and unsigned) as well as typedef declarations, where the behavior is one of the following: * `wrap`: Guarantees that arithmetic operations on the type will wrap on overflow, similar to `-fwrapv`. This suppresses UBSan's integer overflow checks for the attributed type and prevents eager compiler optimizations. * `trap`: Enforces overflow checking for the type, even when global flags like `-fwrapv` would otherwise suppress it. A key aspect of this feature is its interaction with existing mechanisms. `OverflowBehaviorType` takes precedence over global flags and, notably, over entries in the Sanitizer Special Case List (SSCL). This allows developers to "allowlist" critical types for overflow instrumentation, even if they are disabled by a broad rule in an SSCL. Signed-off-by: Justin Stitt <justinstitt@google.com>
44 lines
1.3 KiB
C++
44 lines
1.3 KiB
C++
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -fexperimental-overflow-behavior-types -verify -fsyntax-only -std=c++14
|
|
|
|
#define __wrap __attribute__((overflow_behavior(wrap)))
|
|
#define __no_trap __attribute__((overflow_behavior(trap)))
|
|
|
|
typedef int __ob_wrap wrap_int;
|
|
typedef int __ob_trap no_trap_int;
|
|
|
|
constexpr wrap_int add(wrap_int a, wrap_int b) {
|
|
return a + b;
|
|
}
|
|
|
|
constexpr no_trap_int sub(no_trap_int a, no_trap_int b) {
|
|
return a - b; // expected-note {{-2147483649 is outside the range of representable values}}
|
|
}
|
|
|
|
void constexpr_test() {
|
|
constexpr wrap_int max = 2147483647;
|
|
constexpr wrap_int one = 1;
|
|
static_assert(add(max, one) == -2147483648, "constexpr wrapping failed");
|
|
|
|
constexpr no_trap_int min = -2147483648;
|
|
constexpr no_trap_int one_nw = 1;
|
|
constexpr no_trap_int res = sub(min, one_nw); // expected-error {{constexpr variable 'res' must be initialized by a constant expression}} expected-note {{in call to 'sub(-2147483648, 1)'}}
|
|
}
|
|
|
|
template <typename T>
|
|
void check_deduction_wrap(T) {
|
|
static_assert(__is_same(T, wrap_int), "T should be deduced as wrap_int");
|
|
}
|
|
|
|
template <typename T>
|
|
void check_deduction_no_trap(T) {
|
|
static_assert(__is_same(T, no_trap_int), "T should be deduced as no_trap_int");
|
|
}
|
|
|
|
void template_deduction_test() {
|
|
wrap_int w = 0;
|
|
check_deduction_wrap(w);
|
|
|
|
no_trap_int nw = 0;
|
|
check_deduction_no_trap(nw);
|
|
}
|