Skip to content

Commit

Permalink
[clang-tidy] new check cppcoreguidelines-pro-bounds-pointer-arithmetic
Browse files Browse the repository at this point in the history
Summary:
This check flags all usage of pointer arithmetic, because it could lead
to an
invalid pointer.
Subtraction of two pointers is not flagged by this check.

Pointers should only refer to single objects, and pointer arithmetic is
fragile and easy to get wrong. array_view is a bounds-checked, safe type
for accessing arrays of data.

This rule is part of the "Bounds safety" profile of the C++ Core
Guidelines, see
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-bounds1-dont-use-pointer-arithmetic-use-array_view-instead

Depends on D13313

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D13311

llvm-svn: 250116
  • Loading branch information
mgehre committed Oct 12, 2015
1 parent 9159ce9 commit dc48412
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)

add_clang_library(clangTidyCppCoreGuidelinesModule
CppCoreGuidelinesTidyModule.cpp
ProBoundsPointerArithmeticCheck.cpp
ProTypeConstCastCheck.cpp
ProTypeReinterpretCastCheck.cpp
ProTypeStaticCastDowncastCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../ClangTidy.h"
#include "../ClangTidyModule.h"
#include "../ClangTidyModuleRegistry.h"
#include "ProBoundsPointerArithmeticCheck.h"
#include "ProTypeConstCastCheck.h"
#include "ProTypeReinterpretCastCheck.h"
#include "ProTypeStaticCastDowncastCheck.h"
Expand All @@ -22,6 +23,8 @@ namespace cppcoreguidelines {
class CppCoreGuidelinesModule : public ClangTidyModule {
public:
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
CheckFactories.registerCheck<ProBoundsPointerArithmeticCheck>(
"cppcoreguidelines-pro-bounds-pointer-arithmetic");
CheckFactories.registerCheck<ProTypeConstCastCheck>(
"cppcoreguidelines-pro-type-const-cast");
CheckFactories.registerCheck<ProTypeReinterpretCastCheck>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===--- ProBoundsPointerArithmeticCheck.cpp - clang-tidy------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ProBoundsPointerArithmeticCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;

namespace clang {
namespace tidy {

void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) {
if (!getLangOpts().CPlusPlus)
return;

// Flag all operators +, -, +=, -=, ++, -- that result in a pointer
Finder->addMatcher(
binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-"),
hasOperatorName("+="), hasOperatorName("-=")),
hasType(pointerType()))
.bind("expr"),
this);

Finder->addMatcher(
unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
hasType(pointerType()))
.bind("expr"),
this);

// Array subscript on a pointer (not an array) is also pointer arithmetic
Finder->addMatcher(
arraySubscriptExpr(hasBase(ignoringImpCasts(anyOf(hasType(pointerType()),
hasType(decayedType(hasDecayedType(pointerType())))))))
.bind("expr"),
this);
}

void
ProBoundsPointerArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MatchedExpr = Result.Nodes.getNodeAs<Expr>("expr");

diag(MatchedExpr->getExprLoc(), "do not use pointer arithmetic");
}

} // namespace tidy
} // namespace clang
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===--- ProBoundsPointerArithmeticCheck.h - clang-tidy----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H

#include "../ClangTidy.h"

namespace clang {
namespace tidy {

/// Flags all kinds of pointer arithmetic that have result of pointer type, i.e.
/// +, -, +=, -=, ++, --. In addition, the [] operator on pointers (not on arrays) is flagged.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.html
class ProBoundsPointerArithmeticCheck : public ClangTidyCheck {
public:
ProBoundsPointerArithmeticCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
};

} // namespace tidy
} // namespace clang

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_BOUNDS_POINTER_ARITHMETIC_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cppcoreguidelines-pro-bounds-pointer-arithmetic
===============================================

This check flags all usage of pointer arithmetic, because it could lead to an invalid pointer.
Subtraction of two pointers is not flagged by this check.

Pointers should only refer to single objects, and pointer arithmetic is fragile and easy to get wrong. array_view is a bounds-checked, safe type for accessing arrays of data.

This rule is part of the "Bounds safety" profile of the C++ Core Guidelines, see
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#-bounds1-dont-use-pointer-arithmetic-use-array_view-instead
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ List of clang-tidy Checks
.. toctree::
cert-setlongjmp
cert-variadic-function-def
cppcoreguidelines-pro-bounds-pointer-arithmetic
cppcoreguidelines-pro-type-const-cast
cppcoreguidelines-pro-type-reinterpret-cast
cppcoreguidelines-pro-type-static-cast-downcast
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// RUN: %python %S/check_clang_tidy.py %s cppcoreguidelines-pro-bounds-pointer-arithmetic %t

enum E {
ENUM_LITERAL = 1
};

int i = 4;
int j = 1;
int *p = 0;
int *q = 0;

void fail() {
q = p + 4;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
p = q + i;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
p = q + ENUM_LITERAL;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic

q = p - 1;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
p = q - i;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
p = q - ENUM_LITERAL;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic

p += 4;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
p += i;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
p += ENUM_LITERAL;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic

q -= 1;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
q -= i;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic
q -= ENUM_LITERAL;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use pointer arithmetic

p++;
// CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
++p;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic

p--;
// CHECK-MESSAGES: :[[@LINE-1]]:4: warning: do not use pointer arithmetic
--p;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic

i = p[1];
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use pointer arithmetic
}

struct S {
operator int() const;
};

void f(S &s) {
int *i;
i = i + s;
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not use pointer arithmetic
}

void f2(int i[]) {
i[1] = 0;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use pointer arithmetic
}

void okay() {
int a[3];
i = a[2]; // OK, access to array

p = q;
p = &i;

i++;
++i;
i--;
--i;
i += 1;
i -= 1;
i = j + 1;
i = j - 1;

auto diff = p - q; // OK, result is arithmetic
}

0 comments on commit dc48412

Please sign in to comment.