Skip to content

Commit 4415aaf

Browse files
committed
feat(clang-tidy): Make P + BS / sizeof(*P) opt-outable
1 parent 8305e9f commit 4415aaf

File tree

6 files changed

+54
-6
lines changed

6 files changed

+54
-6
lines changed

clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name,
7070
Options.get("WarnOnSizeOfCompareToConstant", true)),
7171
WarnOnSizeOfPointerToAggregate(
7272
Options.get("WarnOnSizeOfPointerToAggregate", true)),
73-
WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)) {}
73+
WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)),
74+
WarnOnSizeOfPointerArithmeticWithDivisionScaled(Options.get(
75+
"WarnOnSizeOfPointerArithmeticWithDivisionScaled", true)) {}
7476

7577
void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
7678
Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant);
@@ -82,6 +84,8 @@ void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
8284
Options.store(Opts, "WarnOnSizeOfPointerToAggregate",
8385
WarnOnSizeOfPointerToAggregate);
8486
Options.store(Opts, "WarnOnSizeOfPointer", WarnOnSizeOfPointer);
87+
Options.store(Opts, "WarnOnSizeOfPointerArithmeticWithDivisionScaled",
88+
WarnOnSizeOfPointerArithmeticWithDivisionScaled);
8589
}
8690

8791
void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
@@ -306,8 +310,13 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
306310
unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)),
307311
offsetOfExpr()))
308312
.bind("sizeof-in-ptr-arithmetic-scale-expr");
313+
const auto PtrArithmeticIntegerScaleExprInterestingOperatorNames = [this] {
314+
if (WarnOnSizeOfPointerArithmeticWithDivisionScaled)
315+
return binaryOperator(hasAnyOperatorName("*", "/"));
316+
return binaryOperator(hasOperatorName("*"));
317+
};
309318
const auto PtrArithmeticIntegerScaleExpr = binaryOperator(
310-
hasAnyOperatorName("*", "/"),
319+
PtrArithmeticIntegerScaleExprInterestingOperatorNames(),
311320
// sizeof(...) * sizeof(...) and sizeof(...) / sizeof(...) is handled
312321
// by this check on another path.
313322
hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr)),

clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class SizeofExpressionCheck : public ClangTidyCheck {
3131
const bool WarnOnSizeOfCompareToConstant;
3232
const bool WarnOnSizeOfPointerToAggregate;
3333
const bool WarnOnSizeOfPointer;
34+
const bool WarnOnSizeOfPointerArithmeticWithDivisionScaled;
3435
};
3536

3637
} // namespace clang::tidy::bugprone

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ Changes in existing checks
144144
- Improved :doc:`bugprone-sizeof-expression
145145
<clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
146146
usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or
147-
subtracting from a pointer.
147+
subtracting from a pointer directly or when used to scale a numeric value.
148148

149149
- Improved :doc:`bugprone-unchecked-optional-access
150150
<clang-tidy/checks/bugprone/unchecked-optional-access>` to support

clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ and the result is typically unintended, often out of bounds.
221221
``Ptr + sizeof(T)`` will offset the pointer by ``sizeof(T)`` elements,
222222
effectively exponentiating the scaling factor to the power of 2.
223223

224+
Similarly, multiplying or dividing a numeric value with the ``sizeof`` an
225+
element or the whole buffer is suspicious, because the dimensional connection
226+
between the numeric value and the actual ``sizeof`` result can not always be
227+
deduced.
228+
While scaling an integer up (multiplying) with ``sizeof`` is likely **always**
229+
an issue, a scaling down (division) is not always inherently dangerous, in case
230+
the developer is aware that the division happens between an appropriate number
231+
of _bytes_ and a ``sizeof`` value.
232+
Turning :option:`WarnOnSizeOfPointerArithmeticWithDivisionScaledInteger` off
233+
will restrict the warnings to the multiplication case.
234+
224235
This case also checks suspicious ``alignof`` and ``offsetof`` usages in
225236
pointer arithmetic, as both return the "size" in bytes and not elements,
226237
potentially resulting in doubly-scaled offsets.
@@ -299,3 +310,9 @@ Options
299310
``sizeof`` is an expression that produces a pointer (except for a few
300311
idiomatic expressions that are probably intentional and correct).
301312
This detects occurrences of CWE 467. Default is `false`.
313+
314+
.. option:: WarnOnSizeOfPointerArithmeticWithDivisionScaledInteger
315+
316+
When `true`, the check will warn on pointer arithmetic where the
317+
element count is obtained from a division with ``sizeof(...)``,
318+
e.g., ``Ptr + Bytes / sizeof(*T)``. Default is `true`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t -- \
2+
// RUN: -config="{CheckOptions: [{key: bugprone-sizeof-expression.WarnOnSizeOfPointerArithmeticWithDivisionScaled, value: 0}]}"
3+
4+
typedef __SIZE_TYPE__ size_t;
5+
6+
void situational14(int *Buffer, size_t BufferSize) {
7+
int *P = &Buffer[0];
8+
while (P < Buffer + BufferSize / sizeof(*Buffer)) {
9+
// NO-WARNING: This test opted out of "P +- N */ sizeof(...)" warnings.
10+
++P;
11+
}
12+
}

clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,21 +352,30 @@ void good13(void) {
352352
int Buffer[BufferSize];
353353

354354
int *P = &Buffer[0];
355-
while (P < (Buffer + sizeof(Buffer) / sizeof(int))) {
355+
while (P < Buffer + sizeof(Buffer) / sizeof(int)) {
356356
// NO-WARNING: Calculating the element count of the buffer here, which is
357357
// safe with this idiom (as long as the types don't change).
358358
++P;
359359
}
360360

361-
while (P < (Buffer + sizeof(Buffer) / sizeof(Buffer[0]))) {
361+
while (P < Buffer + sizeof(Buffer) / sizeof(Buffer[0])) {
362362
// NO-WARNING: Calculating the element count of the buffer here, which is
363363
// safe with this idiom.
364364
++P;
365365
}
366366

367-
while (P < (Buffer + sizeof(Buffer) / sizeof(*P))) {
367+
while (P < Buffer + sizeof(Buffer) / sizeof(*P)) {
368368
// NO-WARNING: Calculating the element count of the buffer here, which is
369369
// safe with this idiom.
370370
++P;
371371
}
372372
}
373+
374+
void situational14(int *Buffer, size_t BufferSize) {
375+
int *P = &Buffer[0];
376+
while (P < Buffer + BufferSize / sizeof(*Buffer)) {
377+
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
378+
// CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
379+
++P;
380+
}
381+
}

0 commit comments

Comments
 (0)