
Introduce "-fsanitize-undefined-ignore-overflow-pattern=" which can be used to disable sanitizer instrumentation for common overflow-dependent code patterns. For a wide selection of projects, proper overflow sanitization could help catch bugs and solve security vulnerabilities. Unfortunately, in some cases the integer overflow sanitizers are too noisy for their users and are often left disabled. Providing users with a method to disable sanitizer instrumentation of common patterns could mean more projects actually utilize the sanitizers in the first place. One such project that has opted to not use integer overflow (or truncation) sanitizers is the Linux Kernel. There has been some discussion[1] recently concerning mitigation strategies for unexpected arithmetic overflow. This discussion is still ongoing and a succinct article[2] accurately sums up the discussion. In summary, many Kernel developers do not want to introduce more arithmetic wrappers when most developers understand the code patterns as they are. Patterns like: if (base + offset < base) { ... } or while (i--) { ... } or #define SOME -1UL are extremely common in a code base like the Linux Kernel. It is perhaps too much to ask of kernel developers to use arithmetic wrappers in these cases. For example: while (wrapping_post_dec(i)) { ... } which wraps some builtin would not fly. This would incur too many changes to existing code; the code churn would be too much, at least too much to justify turning on overflow sanitizers. Currently, this commit tackles three pervasive idioms: 1. "if (a + b < a)" or some logically-equivalent re-ordering like "if (a > b + a)" 2. "while (i--)" (for unsigned) a post-decrement always overflows here 3. "-1UL, -2UL, etc" negation of unsigned constants will always overflow The patterns that are excluded can be chosen from the following list: - add-overflow-test - post-decr-while - negated-unsigned-const These can be enabled with a comma-separated list: -fsanitize-undefined-ignore-overflow-pattern=add-overflow-test,negated-unsigned-const "all" or "none" may also be used to specify that all patterns should be excluded or that none should be. [1] https://lore.kernel.org/all/202404291502.612E0A10@keescook/ [2] https://lwn.net/Articles/979747/ CCs: @efriedma-quic @kees @jyknight @fmayer @vitalybuka Signed-off-by: Justin Stitt <justinstitt@google.com> Co-authored-by: Bill Wendling <morbo@google.com>
64 lines
1.6 KiB
C
64 lines
1.6 KiB
C
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=all %s -emit-llvm -o - | FileCheck %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=all -fwrapv %s -emit-llvm -o - | FileCheck %s
|
|
|
|
// Check for potential false positives from patterns that _almost_ match classic overflow-dependent or overflow-prone code patterns
|
|
extern unsigned a, b, c;
|
|
extern int u, v, w;
|
|
|
|
extern unsigned some(void);
|
|
|
|
// Make sure all these still have handler paths, we shouldn't be excluding
|
|
// instrumentation of any "near" patterns.
|
|
// CHECK-LABEL: close_but_not_quite
|
|
void close_but_not_quite(void) {
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + b > a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a - b < a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + b < a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + b + 1 < a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + b < a + 1)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (b >= a + b)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + a < a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler.
|
|
if (a + b == a)
|
|
c = 9;
|
|
|
|
// CHECK: br i1{{.*}}handler
|
|
while (--a)
|
|
some();
|
|
}
|
|
|
|
// CHECK-LABEL: function_calls
|
|
void function_calls(void) {
|
|
// CHECK: br i1{{.*}}handler
|
|
if (some() + b < some())
|
|
c = 9;
|
|
}
|
|
|
|
// CHECK-LABEL: not_quite_a_negated_unsigned_const
|
|
void not_quite_a_negated_unsigned_const(void) {
|
|
// CHECK: br i1{{.*}}handler
|
|
a = -b;
|
|
}
|