Skip to content

Commit fccd0da

Browse files
author
Adam Balogh
committed
[clang-tidy] New check: bugprone-misplaced-pointer-arithmetic-in-alloc
Finds cases where an integer expression is added to the result of a memory allocation function instead of its argument. Differential Revision: https://reviews.llvm.org/D71001
1 parent 5181c67 commit fccd0da

9 files changed

+287
-0
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "MacroParenthesesCheck.h"
3131
#include "MacroRepeatedSideEffectsCheck.h"
3232
#include "MisplacedOperatorInStrlenInAllocCheck.h"
33+
#include "MisplacedPointerArithmeticInAllocCheck.h"
3334
#include "MisplacedWideningCastCheck.h"
3435
#include "MoveForwardingReferenceCheck.h"
3536
#include "MultipleStatementMacroCheck.h"
@@ -107,6 +108,8 @@ class BugproneModule : public ClangTidyModule {
107108
"bugprone-macro-repeated-side-effects");
108109
CheckFactories.registerCheck<MisplacedOperatorInStrlenInAllocCheck>(
109110
"bugprone-misplaced-operator-in-strlen-in-alloc");
111+
CheckFactories.registerCheck<MisplacedPointerArithmeticInAllocCheck>(
112+
"bugprone-misplaced-pointer-arithmetic-in-alloc");
110113
CheckFactories.registerCheck<MisplacedWideningCastCheck>(
111114
"bugprone-misplaced-widening-cast");
112115
CheckFactories.registerCheck<MoveForwardingReferenceCheck>(

clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_clang_library(clangTidyBugproneModule
2222
MacroParenthesesCheck.cpp
2323
MacroRepeatedSideEffectsCheck.cpp
2424
MisplacedOperatorInStrlenInAllocCheck.cpp
25+
MisplacedPointerArithmeticInAllocCheck.cpp
2526
MisplacedWideningCastCheck.cpp
2627
MoveForwardingReferenceCheck.cpp
2728
MultipleStatementMacroCheck.cpp
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//===--- MisplacedPointerArithmeticInAllocCheck.cpp - clang-tidy-----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "MisplacedPointerArithmeticInAllocCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
13+
using namespace clang::ast_matchers;
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace bugprone {
18+
19+
void MisplacedPointerArithmeticInAllocCheck::registerMatchers(
20+
MatchFinder *Finder) {
21+
const auto AllocFunc = functionDecl(
22+
anyOf(hasName("::malloc"), hasName("std::malloc"), hasName("::alloca"),
23+
hasName("::calloc"), hasName("std::calloc"), hasName("::realloc"),
24+
hasName("std::realloc")));
25+
26+
const auto AllocFuncPtr =
27+
varDecl(hasType(isConstQualified()),
28+
hasInitializer(ignoringParenImpCasts(
29+
declRefExpr(hasDeclaration(AllocFunc)))));
30+
31+
const auto AdditiveOperator =
32+
binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")));
33+
34+
const auto IntExpr = expr(hasType(isInteger()));
35+
36+
const auto AllocCall = callExpr(callee(decl(anyOf(AllocFunc, AllocFuncPtr))));
37+
38+
Finder->addMatcher(
39+
binaryOperator(
40+
AdditiveOperator,
41+
hasLHS(anyOf(AllocCall, castExpr(hasSourceExpression(AllocCall)))),
42+
hasRHS(IntExpr))
43+
.bind("PtrArith"),
44+
this);
45+
46+
const auto New = cxxNewExpr(unless(isArray()));
47+
48+
Finder->addMatcher(binaryOperator(AdditiveOperator,
49+
hasLHS(anyOf(New, castExpr(New))),
50+
hasRHS(IntExpr))
51+
.bind("PtrArith"),
52+
this);
53+
54+
const auto ArrayNew = cxxNewExpr(isArray());
55+
56+
Finder->addMatcher(binaryOperator(AdditiveOperator,
57+
hasLHS(anyOf(ArrayNew, castExpr(ArrayNew))),
58+
hasRHS(IntExpr))
59+
.bind("PtrArith"),
60+
this);
61+
}
62+
63+
void MisplacedPointerArithmeticInAllocCheck::check(
64+
const MatchFinder::MatchResult &Result) {
65+
const auto *PtrArith = Result.Nodes.getNodeAs<BinaryOperator>("PtrArith");
66+
const Expr *AllocExpr = PtrArith->getLHS()->IgnoreParenCasts();
67+
std::string CallName;
68+
69+
if (const auto *Call = dyn_cast<CallExpr>(AllocExpr)) {
70+
const NamedDecl *Func = Call->getDirectCallee();
71+
if (!Func) {
72+
Func = cast<NamedDecl>(Call->getCalleeDecl());
73+
}
74+
CallName = Func->getName().str();
75+
} else {
76+
const auto *New = cast<CXXNewExpr>(AllocExpr);
77+
if (New->isArray()) {
78+
CallName = "operator new[]";
79+
} else {
80+
const auto *CtrE = New->getConstructExpr();
81+
if (!CtrE->getArg(CtrE->getNumArgs() - 1)
82+
->getType()
83+
->isIntegralOrEnumerationType())
84+
return;
85+
CallName = "operator new";
86+
}
87+
}
88+
89+
const SourceRange OldRParen = SourceRange(PtrArith->getLHS()->getEndLoc());
90+
const StringRef RParen =
91+
Lexer::getSourceText(CharSourceRange::getTokenRange(OldRParen),
92+
*Result.SourceManager, getLangOpts());
93+
const SourceLocation NewRParen = Lexer::getLocForEndOfToken(
94+
PtrArith->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
95+
96+
diag(PtrArith->getBeginLoc(),
97+
"arithmetic operation is applied to the result of %0() instead of its "
98+
"size-like argument")
99+
<< CallName << FixItHint::CreateRemoval(OldRParen)
100+
<< FixItHint::CreateInsertion(NewRParen, RParen);
101+
}
102+
103+
} // namespace bugprone
104+
} // namespace tidy
105+
} // namespace clang
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===--- MisplacedPointerArithmeticInAllocCheck.h - clang-tidy---*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_ALLOC_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_ALLOC_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang {
15+
namespace tidy {
16+
namespace bugprone {
17+
18+
/// Finds cases where an integer is added to or subracted from the result of a
19+
/// memory allocation function instead of its argument.
20+
///
21+
/// For the user-facing documentation see:
22+
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-misplaced-operator-in-alloc.html
23+
class MisplacedPointerArithmeticInAllocCheck : public ClangTidyCheck {
24+
public:
25+
MisplacedPointerArithmeticInAllocCheck(StringRef Name,
26+
ClangTidyContext *Context)
27+
: ClangTidyCheck(Name, Context) {}
28+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
29+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
30+
};
31+
32+
} // namespace bugprone
33+
} // namespace tidy
34+
} // namespace clang
35+
36+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MISPLACED_OPERATOR_IN_ALLOC_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ Improvements to clang-tidy
7070
New checks
7171
^^^^^^^^^^
7272

73+
- New :doc:`bugprone-misplaced-pointer-arithmetic-in-alloc
74+
<clang-tidy/checks/bugprone-misplaced-pointer-arithmetic-in-alloc>` check.
75+
76+
Finds cases where an integer expression is added to or subtracted from the
77+
result of a memory allocation function (``malloc()``, ``calloc()``,
78+
``realloc()``, ``alloca()``) instead of its argument.
79+
7380
- New :doc:`bugprone-reserved-identifier
7481
<clang-tidy/checks/bugprone-reserved-identifier>` check.
7582

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.. title:: clang-tidy - bugprone-misplaced-pointer-arithmetic-in-alloc
2+
3+
bugprone-misplaced-pointer-artithmetic-in-alloc
4+
===============================================
5+
6+
Finds cases where an integer expression is added to or subtracted from the
7+
result of a memory allocation function (``malloc()``, ``calloc()``,
8+
``realloc()``, ``alloca()``) instead of its argument. The check detects error
9+
cases even if one of these functions is called by a constant function pointer.
10+
11+
Example code:
12+
13+
.. code-block:: c
14+
15+
void bad_malloc(int n) {
16+
char *p = (char*) malloc(n) + 10;
17+
}
18+
19+
20+
The suggested fix is to add the integer expression to the argument of
21+
``malloc`` and not to its result. In the example above the fix would be
22+
23+
.. code-block:: c
24+
25+
char *p = (char*) malloc(n + 10);

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Clang-Tidy Checks
6565
`bugprone-macro-parentheses <bugprone-macro-parentheses.html>`_, "Yes"
6666
`bugprone-macro-repeated-side-effects <bugprone-macro-repeated-side-effects.html>`_,
6767
`bugprone-misplaced-operator-in-strlen-in-alloc <bugprone-misplaced-operator-in-strlen-in-alloc.html>`_, "Yes"
68+
`bugprone-misplaced-pointer-arithmetic-in-alloc <bugprone-misplaced-pointer-arithmetic-in-alloc.html>`_, "Yes"
6869
`bugprone-misplaced-widening-cast <bugprone-misplaced-widening-cast.html>`_,
6970
`bugprone-move-forwarding-reference <bugprone-move-forwarding-reference.html>`_, "Yes"
7071
`bugprone-multiple-statement-macro <bugprone-multiple-statement-macro.html>`_,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %check_clang_tidy %s bugprone-misplaced-pointer-arithmetic-in-alloc %t
2+
3+
typedef __typeof(sizeof(int)) size_t;
4+
void *malloc(size_t);
5+
void *alloca(size_t);
6+
void *calloc(size_t, size_t);
7+
void *realloc(void *, size_t);
8+
9+
void bad_malloc(int n) {
10+
char *p = (char *)malloc(n) + 10;
11+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of malloc() instead of its size-like argument
12+
// CHECK-FIXES: char *p = (char *)malloc(n + 10);
13+
14+
p = (char *)malloc(n) - 10;
15+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of malloc() instead of its size-like argument
16+
// CHECK-FIXES: p = (char *)malloc(n - 10);
17+
18+
p = (char *)malloc(n) + n;
19+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of malloc() instead of its size-like argument
20+
// CHECK-FIXES: p = (char *)malloc(n + n);
21+
22+
p = (char *)malloc(n) - (n + 10);
23+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of malloc() instead of its size-like argument
24+
// CHECK-FIXES: p = (char *)malloc(n - (n + 10));
25+
26+
p = (char *)malloc(n) - n + 10;
27+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of malloc() instead of its size-like argument
28+
// CHECK-FIXES: p = (char *)malloc(n - n) + 10;
29+
// FIXME: should be p = (char *)malloc(n - n + 10);
30+
}
31+
32+
void bad_alloca(int n) {
33+
char *p = (char *)alloca(n) + 10;
34+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of alloca() instead of its size-like argument
35+
// CHECK-FIXES: char *p = (char *)alloca(n + 10);
36+
}
37+
38+
void bad_realloc(char *s, int n) {
39+
char *p = (char *)realloc(s, n) + 10;
40+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of realloc() instead of its size-like argument
41+
// CHECK-FIXES: char *p = (char *)realloc(s, n + 10);
42+
}
43+
44+
void bad_calloc(int n, int m) {
45+
char *p = (char *)calloc(m, n) + 10;
46+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of calloc() instead of its size-like argument
47+
// CHECK-FIXES: char *p = (char *)calloc(m, n + 10);
48+
}
49+
50+
void (*(*const alloc_ptr)(size_t)) = malloc;
51+
52+
void bad_indirect_alloc(int n) {
53+
char *p = (char *)alloc_ptr(n) + 10;
54+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of alloc_ptr() instead of its size-like argument
55+
// CHECK-FIXES: char *p = (char *)alloc_ptr(n + 10);
56+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %check_clang_tidy %s bugprone-misplaced-pointer-arithmetic-in-alloc %t
2+
3+
class C {
4+
int num;
5+
public:
6+
explicit C(int n) : num(n) {}
7+
};
8+
9+
void bad_new(int n, int m) {
10+
C *p = new C(n) + 10;
11+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
12+
// CHECK-FIXES: C *p = new C(n + 10);
13+
14+
p = new C(n) - 10;
15+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
16+
// CHECK-FIXES: p = new C(n - 10);
17+
18+
p = new C(n) + m;
19+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
20+
// CHECK-FIXES: p = new C(n + m);
21+
22+
p = new C(n) - (m + 10);
23+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
24+
// CHECK-FIXES: p = new C(n - (m + 10));
25+
26+
p = new C(n) - m + 10;
27+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new() instead of its size-like argument
28+
// CHECK-FIXES: p = new C(n - m) + 10;
29+
// FIXME: Should be p = new C(n - m + 10);
30+
}
31+
32+
void bad_new_array(int n, int m) {
33+
char *p = new char[n] + 10;
34+
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: arithmetic operation is applied to the result of operator new[]() instead of its size-like argument
35+
// CHECK-FIXES: char *p = new char[n + 10];
36+
37+
p = new char[n] - 10;
38+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new[]() instead of its size-like argument
39+
// CHECK-FIXES: p = new char[n - 10];
40+
41+
p = new char[n] + m;
42+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new[]() instead of its size-like argument
43+
// CHECK-FIXES: p = new char[n + m];
44+
45+
p = new char[n] - (m + 10);
46+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new[]() instead of its size-like argument
47+
// CHECK-FIXES: p = new char[n - (m + 10)];
48+
49+
p = new char[n] - m + 10;
50+
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: arithmetic operation is applied to the result of operator new[]() instead of its size-like argument
51+
// CHECK-FIXES: p = new char[n - m] + 10;
52+
// FIXME: should be p = new char[n - m + 10];
53+
}

0 commit comments

Comments
 (0)