diff options
7 files changed, 189 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt index d35b9a56f94..6147914a9fe 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyCppCoreGuidelinesModule CppCoreGuidelinesTidyModule.cpp + ProBoundsPointerArithmeticCheck.cpp ProTypeConstCastCheck.cpp ProTypeReinterpretCastCheck.cpp ProTypeStaticCastDowncastCheck.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp index 358bd6ec8fd..07ba15a8b4a 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -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" @@ -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>( diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp new file mode 100644 index 00000000000..15ea27a4462 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp @@ -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 diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h new file mode 100644 index 00000000000..f3a3fb18cff --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.h @@ -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 diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst new file mode 100644 index 00000000000..60582eb73eb --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-pro-bounds-pointer-arithmetic.rst @@ -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 diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index c46a7960cd0..c5496361532 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -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 diff --git a/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp new file mode 100644 index 00000000000..b765f00bd37 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/cppcoreguidelines-pro-bounds-pointer-arithmetic.cpp @@ -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 +} |