Skip to content

Commit c55507b

Browse files
committed
rename some patterns, rewrite docs
From Vitaly's review on llvm#104889: * remove unused variable in tests * rename `post-decr-while` --> `unsigned-post-decr-while` * split `add-overflow-test` into `add-unsigned-overflow-test` and `add-signed-overflow-test` * be more clear about defaults within docs * add table to docs Signed-off-by: Justin Stitt <justinstitt@google.com>
1 parent 7854b16 commit c55507b

File tree

10 files changed

+101
-32
lines changed

10 files changed

+101
-32
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -451,28 +451,34 @@ Sanitizers
451451

452452
- Added the ``-fsanitize-undefined-ignore-overflow-pattern`` flag which can be
453453
used to disable specific overflow-dependent code patterns. The supported
454-
patterns are: ``add-overflow-test``, ``negated-unsigned-const``, and
455-
``post-decr-while``. The sanitizer instrumentation can be toggled off for all
456-
available patterns by specifying ``all``. Conversely, you can disable all
457-
exclusions with ``none``.
454+
patterns are: ``add-signed-overflow-test``, ``add-unsigned-overflow-test``,
455+
``negated-unsigned-const``, and ``unsigned-post-decr-while``. The sanitizer
456+
instrumentation can be toggled off for all available patterns by specifying
457+
``all``. Conversely, you may disable all exclusions with ``none`` which is
458+
the default.
458459

459460
.. code-block:: c++
460461

461-
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-overflow-test``
462+
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-unsigned-overflow-test``
462463
int common_overflow_check_pattern(unsigned base, unsigned offset) {
463464
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings, won't be instrumented
464465
}
465466
467+
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test``
468+
int common_overflow_check_pattern_signed(signed int base, signed int offset) {
469+
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings, won't be instrumented
470+
}
471+
466472
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=negated-unsigned-const``
467473
void negation_overflow() {
468474
unsigned long foo = -1UL; // No longer causes a negation overflow warning
469475
unsigned long bar = -2UL; // and so on...
470476
}
471477

472-
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=post-decr-while``
478+
/// specified with ``-fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while``
473479
void while_post_decrement() {
474480
unsigned char count = 16;
475-
while (count--) { /* ... */} // No longer causes unsigned-integer-overflow sanitizer to trip
481+
while (count--) { /* ... */ } // No longer causes unsigned-integer-overflow sanitizer to trip
476482
}
477483
478484
Many existing projects have a large amount of these code patterns present.

clang/docs/UndefinedBehaviorSanitizer.rst

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -314,26 +314,55 @@ Currently, this option supports three overflow-dependent code idioms:
314314
unsigned long foo = -1UL; // No longer causes a negation overflow warning
315315
unsigned long bar = -2UL; // and so on...
316316

317-
``post-decr-while``
317+
``unsigned-post-decr-while``
318318

319319
.. code-block:: c++
320320

321-
/// -fsanitize-undefined-ignore-overflow-pattern=post-decr-while
321+
/// -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while
322322
unsigned char count = 16;
323323
while (count--) { /* ... */ } // No longer causes unsigned-integer-overflow sanitizer to trip
324324
325-
``add-overflow-test``
325+
``add-signed-overflow-test,add-unsigned-overflow-test``
326326

327327
.. code-block:: c++
328328

329-
/// -fsanitize-undefined-ignore-overflow-pattern=add-overflow-test
329+
/// -fsanitize-undefined-ignore-overflow-pattern=add-(signed|unsigned)-overflow-test
330330
if (base + offset < base) { /* ... */ } // The pattern of `a + b < a`, and other re-orderings,
331-
// won't be instrumented (same for signed types)
331+
// won't be instrumented (signed or unsigned types)
332+
333+
Of the two arithmetic overflow sanitizer kinds ``unsigned-integer-overflow``
334+
and ``signed-integer-overflow``, ignored overflow patterns exclude
335+
instrumentation from one of them.
336+
337+
.. list-table:: Overflow Pattern Types
338+
:widths: 30 50
339+
:header-rows: 1
340+
341+
* - Pattern
342+
- Sanitizer
343+
* - negated-unsigned-const
344+
- unsigned-integer-overflow
345+
* - unsigned-post-decr-while
346+
- unsigned-integer-overflow
347+
* - add-unsigned-overflow-test
348+
- unsigned-integer-overflow
349+
* - add-signed-overflow-test
350+
- signed-integer-overflow
351+
352+
353+
354+
Ignoring overflow patterns has no effect on the definedness of the arithmetic
355+
within the pattern. Since ``add-signed-overflow-test`` works with the
356+
``signed-integer-overflow`` sanitizer instrumentation for code matching this
357+
overflow pattern is ommitted which may cause eager UB optimizations. One may
358+
remedy this with ``-fwrapv`` or ``-fno-strict-overflow``.
332359

333360
You can enable all exclusions with
334361
``-fsanitize-undefined-ignore-overflow-pattern=all`` or disable all exclusions
335-
with ``-fsanitize-undefined-ignore-overflow-pattern=none``. Specifying ``none``
336-
has precedence over other values.
362+
with ``-fsanitize-undefined-ignore-overflow-pattern=none``. If
363+
``-fsanitize-undefined-ignore-overflow-pattern`` is not specified ``none`` is
364+
implied. Specifying ``none`` alongside other values also implies ``none`` as
365+
``none`` has precedence over other values -- including ``all``.
337366

338367
Issue Suppression
339368
=================

clang/include/clang/Basic/LangOptions.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,13 @@ class LangOptionsBase {
375375
/// Exclude all overflow patterns (below)
376376
All = 1 << 1,
377377
/// if (a + b < a)
378-
AddOverflowTest = 1 << 2,
378+
AddSignedOverflowTest = 1 << 2,
379+
/// if (a + b < a)
380+
AddUnsignedOverflowTest = 1 << 3,
379381
/// -1UL
380-
NegUnsignedConst = 1 << 3,
382+
NegUnsignedConst = 1 << 4,
381383
/// while (count--)
382-
PostDecrInWhile = 1 << 4,
384+
PostDecrInWhile = 1 << 5,
383385
};
384386

385387
enum class DefaultVisiblityExportMapping {

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2568,7 +2568,7 @@ defm sanitize_stats : BoolOption<"f", "sanitize-stats",
25682568
def fsanitize_undefined_ignore_overflow_pattern_EQ : CommaJoined<["-"], "fsanitize-undefined-ignore-overflow-pattern=">,
25692569
HelpText<"Specify the overflow patterns to exclude from artihmetic sanitizer instrumentation">,
25702570
Visibility<[ClangOption, CC1Option]>,
2571-
Values<"none,all,add-overflow-test,negated-unsigned-const,post-decr-while">,
2571+
Values<"none,all,add-unsigned-overflow-test,add-signed-overflow-test,negated-unsigned-const,unsigned-post-decr-while">,
25722572
MarshallingInfoStringVector<LangOpts<"OverflowPatternExclusionValues">>;
25732573
def fsanitize_thread_memory_access : Flag<["-"], "fsanitize-thread-memory-access">,
25742574
Group<f_clang_Group>,

clang/lib/AST/Expr.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4806,6 +4806,34 @@ getOverflowPatternBinOp(const BinaryOperator *E) {
48064806
return {};
48074807
}
48084808

4809+
/// Compute and set the OverflowPatternExclusion bit based on whether the
4810+
/// BinaryOperator expression matches an overflow pattern being ignored by
4811+
/// -fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test or
4812+
/// -fsanitize-undefined-ignore-overflow-pattern=add-unsigned-overflow-test
4813+
static void computeOverflowPatternExclusion(const ASTContext &Ctx,
4814+
const BinaryOperator *E) {
4815+
bool AddSignedOverflowTest = Ctx.getLangOpts().isOverflowPatternExcluded(
4816+
LangOptions::OverflowPatternExclusionKind::AddSignedOverflowTest);
4817+
bool AddUnsignedOverflowTest = Ctx.getLangOpts().isOverflowPatternExcluded(
4818+
LangOptions::OverflowPatternExclusionKind::AddUnsignedOverflowTest);
4819+
4820+
if (!AddSignedOverflowTest && !AddUnsignedOverflowTest)
4821+
return;
4822+
4823+
std::optional<BinaryOperator *> Result = getOverflowPatternBinOp(E);
4824+
4825+
if (!Result.has_value())
4826+
return;
4827+
4828+
QualType AdditionResultType = Result.value()->getType();
4829+
4830+
if (AddSignedOverflowTest && AdditionResultType->isSignedIntegerType())
4831+
Result.value()->setExcludedOverflowPattern(true);
4832+
else if (AddUnsignedOverflowTest &&
4833+
AdditionResultType->isUnsignedIntegerType())
4834+
Result.value()->setExcludedOverflowPattern(true);
4835+
}
4836+
48094837
BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
48104838
Opcode opc, QualType ResTy, ExprValueKind VK,
48114839
ExprObjectKind OK, SourceLocation opLoc,
@@ -4818,12 +4846,7 @@ BinaryOperator::BinaryOperator(const ASTContext &Ctx, Expr *lhs, Expr *rhs,
48184846
BinaryOperatorBits.ExcludedOverflowPattern = false;
48194847
SubExprs[LHS] = lhs;
48204848
SubExprs[RHS] = rhs;
4821-
if (Ctx.getLangOpts().isOverflowPatternExcluded(
4822-
LangOptions::OverflowPatternExclusionKind::AddOverflowTest)) {
4823-
std::optional<BinaryOperator *> Result = getOverflowPatternBinOp(this);
4824-
if (Result.has_value())
4825-
Result.value()->BinaryOperatorBits.ExcludedOverflowPattern = true;
4826-
}
4849+
computeOverflowPatternExclusion(Ctx, this);
48274850
BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
48284851
if (hasStoredFPFeatures())
48294852
setStoredFPFeatures(FPFeatures);

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2785,7 +2785,7 @@ static bool matchesPostDecrInWhile(const UnaryOperator *UO, bool isInc,
27852785
if (isInc || isPre)
27862786
return false;
27872787

2788-
// -fsanitize-undefined-ignore-overflow-pattern=post-decr-while
2788+
// -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while
27892789
if (!Ctx.getLangOpts().isOverflowPatternExcluded(
27902790
LangOptions::OverflowPatternExclusionKind::PostDecrInWhile))
27912791
return false;

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,9 +1453,12 @@ static int parseOverflowPatternExclusionValues(const Driver &D,
14531453
llvm::StringSwitch<int>(Value)
14541454
.Case("none", LangOptionsBase::None)
14551455
.Case("all", LangOptionsBase::All)
1456-
.Case("add-overflow-test", LangOptionsBase::AddOverflowTest)
1456+
.Case("add-unsigned-overflow-test",
1457+
LangOptionsBase::AddUnsignedOverflowTest)
1458+
.Case("add-signed-overflow-test",
1459+
LangOptionsBase::AddSignedOverflowTest)
14571460
.Case("negated-unsigned-const", LangOptionsBase::NegUnsignedConst)
1458-
.Case("post-decr-while", LangOptionsBase::PostDecrInWhile)
1461+
.Case("unsigned-post-decr-while", LangOptionsBase::PostDecrInWhile)
14591462
.Default(0);
14601463
if (E == 0)
14611464
D.Diag(clang::diag::err_drv_unsupported_option_argument)

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4274,9 +4274,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
42744274
llvm::StringSwitch<unsigned>(A->getValue(i))
42754275
.Case("none", LangOptionsBase::None)
42764276
.Case("all", LangOptionsBase::All)
4277-
.Case("add-overflow-test", LangOptionsBase::AddOverflowTest)
4277+
.Case("add-unsigned-overflow-test",
4278+
LangOptionsBase::AddUnsignedOverflowTest)
4279+
.Case("add-signed-overflow-test",
4280+
LangOptionsBase::AddSignedOverflowTest)
42784281
.Case("negated-unsigned-const", LangOptionsBase::NegUnsignedConst)
4279-
.Case("post-decr-while", LangOptionsBase::PostDecrInWhile)
4282+
.Case("unsigned-post-decr-while",
4283+
LangOptionsBase::PostDecrInWhile)
42804284
.Default(0);
42814285
}
42824286
}

clang/test/CodeGen/ignore-overflow-pattern-false-pos.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
// Check for potential false positives from patterns that _almost_ match classic overflow-dependent or overflow-prone code patterns
55
extern unsigned a, b, c;
6-
extern int u, v, w;
76

87
extern unsigned some(void);
98

clang/test/CodeGen/ignore-overflow-pattern.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// 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
22
// 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
3-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=add-overflow-test %s -emit-llvm -o - | FileCheck %s --check-prefix=ADD
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=add-signed-overflow-test,add-unsigned-overflow-test %s -emit-llvm -o - | FileCheck %s --check-prefix=ADD
44
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=negated-unsigned-const %s -emit-llvm -o - | FileCheck %s --check-prefix=NEGATE
5-
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=post-decr-while %s -emit-llvm -o - | FileCheck %s --check-prefix=WHILE
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsanitize=signed-integer-overflow,unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=unsigned-post-decr-while %s -emit-llvm -o - | FileCheck %s --check-prefix=WHILE
66

77
// Ensure some common overflow-dependent or overflow-prone code patterns don't
88
// trigger the overflow sanitizers. In many cases, overflow warnings caused by
@@ -25,6 +25,7 @@
2525
// CHECK-NOT: handle{{.*}}overflow
2626

2727
extern unsigned a, b, c;
28+
extern int u, v;
2829
extern unsigned some(void);
2930

3031
// ADD-LABEL: @basic_commutativity
@@ -50,6 +51,8 @@ void basic_commutativity(void) {
5051
c = 9;
5152
if (b > b + a)
5253
c = 9;
54+
if (u + v < u)
55+
c = 9;
5356
}
5457

5558
// ADD-LABEL: @arguments_and_commutativity

0 commit comments

Comments
 (0)