njames93 updated this revision to Diff 237367.
njames93 added a comment.

Tweaked a few documentation issues


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D72488/new/

https://reviews.llvm.org/D72488

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.cpp
  clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-oop57-cpp.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cert-oop57-cpp.cpp
@@ -0,0 +1,90 @@
+// RUN: %check_clang_tidy %s cert-oop57-cpp %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: cert-oop57-cpp.MemSetNames, value: mymemset}, \
+// RUN:  {key: cert-oop57-cpp.MemCpyNames, value: mymemcpy}, \
+// RUN:  {key: cert-oop57-cpp.MemCmpNames, value: mymemcmp}]}' \
+// RUN: --
+
+void mymemset(void *, unsigned char, decltype(sizeof(int)));
+void mymemcpy(void *, const void *, decltype(sizeof(int)));
+int mymemcmp(const void *, const void *, decltype(sizeof(int)));
+
+namespace std {
+void memset(void *, unsigned char, decltype(sizeof(int)));
+void memcpy(void *, const void *, decltype(sizeof(int)));
+void memmove(void *, const void *, decltype(sizeof(int)));
+void strcpy(void *, const void *, decltype(sizeof(int)));
+int memcmp(const void *, const void *, decltype(sizeof(int)));
+int strcmp(const void *, const void *, decltype(sizeof(int)));
+} // namespace std
+
+struct Trivial {
+  int I;
+  int J;
+};
+
+struct NonTrivial {
+  int I;
+  int J;
+
+  NonTrivial() : I(0), J(0) {}
+  NonTrivial &operator=(const NonTrivial &Other) {
+    I = Other.I;
+    J = Other.J;
+    return *this;
+  }
+
+  bool operator==(const Trivial &Other) const {
+    return I == Other.I && J == Other.J;
+  }
+  bool operator!=(const Trivial &Other) const {
+    return !(*this == Other);
+  }
+};
+
+void foo(const Trivial &Other) {
+  Trivial Data;
+  std::memset(&Data, 0, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: Calling 'std::memset' on a non trivially default constructible class is undefined
+  std::memset(&Data, 0, sizeof(Trivial));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: Calling 'std::memset' on a non trivially default constructible class is undefined
+  std::memcpy(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: Calling 'std::memcpy' on a non trivially copyable class is undefined
+  std::memmove(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: Calling 'std::memmove' on a non trivially copyable class is undefined
+  std::strcpy(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: Calling 'std::strcpy' on a non trivially copyable class is undefined
+  std::memcmp(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'std::memcmp'
+  std::strcmp(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'std::strcmp'
+}
+
+void bar(const NonTrivial &Other) {
+  NonTrivial Data;
+  std::memset(&Data, 0, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'std::memset' on a non trivially default constructible class is undefined
+  // Check it detects sizeof(Type) as well as sizeof(Instantiation)
+  std::memset(&Data, 0, sizeof(NonTrivial));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'std::memset' on a non trivially default constructible class is undefined
+  std::memcpy(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'std::memcpy' on a non trivially copyable class is undefined
+  std::memmove(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'std::memmove' on a non trivially copyable class is undefined
+  std::strcpy(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'std::strcpy' on a non trivially copyable class is undefined
+  std::memcmp(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'std::memcmp'
+  std::strcmp(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'std::strcmp'
+}
+
+void baz(const NonTrivial &Other) {
+  NonTrivial Data;
+  mymemset(&Data, 0, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'mymemset' on a non trivially default constructible class is undefined
+  mymemcpy(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Calling 'mymemcpy' on a non trivially copyable class is undefined
+  mymemcmp(&Data, &Other, sizeof(Data));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: consider using comparison operators instead of calling 'mymemcmp'
+}
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -99,6 +99,7 @@
    `cert-mem57-cpp <cert-mem57-cpp.html>`_,
    `cert-msc50-cpp <cert-msc50-cpp.html>`_,
    `cert-msc51-cpp <cert-msc51-cpp.html>`_,
+   `cert-oop57-cpp <cert-oop57-cpp.html>`_,
    `cert-oop58-cpp <cert-oop58-cpp.html>`_,
    `clang-analyzer-core.DynamicTypePropagation <clang-analyzer-core.DynamicTypePropagation.html>`_,
    `clang-analyzer-core.uninitialized.CapturedBlockVariable <clang-analyzer-core.uninitialized.CapturedBlockVariable.html>`_,
Index: clang-tools-extra/docs/clang-tidy/checks/cert-oop57-cpp.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cert-oop57-cpp.rst
@@ -0,0 +1,33 @@
+.. title:: clang-tidy - cert-oop57-cpp
+
+cert-oop57-cpp
+==============
+
+Flags use of the c standard library functions ``memset``, ``memcpy``,
+``memmove``, ``strcpy``, ``memcmp`` and ``strcmp`` on non trivial types.
+
+Options
+-------
+
+.. option:: MemSetNames
+
+  Specify extra functions to flag on that act similarily to memset.
+  Default is an empty string
+  The check will always detect the function: ``memset``
+
+.. option:: MemCpyNames
+
+  Specify extra functions to flag on that act similarily to memcpy.
+  Default is an empty string
+  The check will always detect the functions: ``memcpy``, ``memmove`` and ``strcpy``
+
+.. option:: MemCmpNames
+
+  Specify extra functions to flag on that act similarily to memcmp.
+  Default is an empty string
+  The check will always detect the functions: ``memcmp`` and ``strcmp``
+
+This check corresponds to the CERT C++ Coding Standard rule
+`OOP57-CPP. Prefer special member functions and overloaded operators to C 
+Standard Library functions
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/OOP57-CPP.+Prefer+special+member+functions+and+overloaded+operators+to+C+Standard+Library+functions>`_.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -106,6 +106,12 @@
   Checks if an object of type with extended alignment is allocated by using
   the default ``operator new``.
 
+- New :doc:`cert-oop57-cpp
+  <clang-tidy/checks/cert-oop57-cpp>` check.
+  
+  Flags use of the c standard library functions ``memset``, ``memcpy``,
+  ``memmove``, ``strcpy``, ``memcmp`` and ``strcmp`` on non trivial types.
+  
 - New :doc:`cert-oop58-cpp
   <clang-tidy/checks/cert-oop58-cpp>` check.
 
Index: clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.h
@@ -0,0 +1,40 @@
+//===--- NotTrivialTypesLibcMemoryCallsCheck.h - clang-tidy -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_NOTTRIVIALTYPESLIBCMEMORYCALLSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_NOTTRIVIALTYPESLIBCMEMORYCALLSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// This check flags use of the c standard library functions 'memset', 'memcpy',
+/// 'memmove', 'strcpy', 'memcmp' and 'strcmp' on non trivial types.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-oop57-cpp.html
+class NotTrivialTypesLibcMemoryCallsCheck : public ClangTidyCheck {
+public:
+  NotTrivialTypesLibcMemoryCallsCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const std::string MemSetNames;
+  const std::string MemCpyNames;
+  const std::string MemCmpNames;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_NOTTRIVIALTYPESLIBCMEMORYCALLSCHECK_H
Index: clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cert/NotTrivialTypesLibcMemoryCallsCheck.cpp
@@ -0,0 +1,145 @@
+//===--- NotTrivialTypesLibcMemoryCallsCheck.cpp - clang-tidy ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NotTrivialTypesLibcMemoryCallsCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+namespace {
+AST_MATCHER(CXXRecordDecl, isTriviallyDefaultConstructible) {
+  return Node.hasTrivialDefaultConstructor();
+}
+AST_MATCHER(CXXRecordDecl, isTriviallyCopyable) {
+  return Node.hasTrivialCopyAssignment() && Node.hasTrivialCopyConstructor();
+}
+} // namespace
+
+static const char BuiltinMemSet[] = "::std::memset;"
+                                    "::memset;";
+static const char BuiltinMemCpy[] = "::std::memcpy;"
+                                    "::memcpy;"
+                                    "::std::memmove;"
+                                    "::memmove;"
+                                    "::std::strcpy;"
+                                    "::strcpy;";
+static const char BuiltinMemCmp[] = "::std::memcmp;"
+                                    "::memcmp;"
+                                    "::std::strcmp;"
+                                    "::strcmp;";
+static constexpr llvm::StringRef EqualityComparison[] = {"operator==",
+                                                         "operator!="};
+
+static std::string getName(const CallExpr &Caller) {
+  llvm::SmallVector<char, 64> Buffer;
+  llvm::raw_svector_ostream OS(Buffer);
+  cast<NamedDecl>(Caller.getCalleeDecl())->printQualifiedName(OS);
+  return OS.str().trim(':');
+}
+
+static std::vector<llvm::StringRef> toStringRefVec(const std::vector<std::string> & Items){
+  return std::vector<llvm::StringRef>(Items.begin(), Items.end());
+}
+
+NotTrivialTypesLibcMemoryCallsCheck::NotTrivialTypesLibcMemoryCallsCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      MemSetNames(Options.get("MemSetNames", "")),
+      MemCpyNames(Options.get("MemCpyNames", "")),
+      MemCmpNames(Options.get("MemCmpNames", "")) {}
+
+void NotTrivialTypesLibcMemoryCallsCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "MemSetNames", MemSetNames);
+  Options.store(Opts, "MemCpyNames", MemCpyNames);
+  Options.store(Opts, "MemCmpNames", MemCmpNames);
+}
+
+void NotTrivialTypesLibcMemoryCallsCheck::registerMatchers(
+    MatchFinder *Finder) {
+
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  using namespace ast_matchers::internal;
+  auto IsStructPointer = [](Matcher<CXXRecordDecl> Constraint = anything(),
+                            bool Bind = false) {
+    return expr(unaryOperator(
+        hasOperatorName("&"),
+        hasUnaryOperand(declRefExpr(
+            allOf(hasType(cxxRecordDecl(Constraint)),
+                  hasType(Bind ? qualType().bind("Record") : qualType()))))));
+  };
+  auto IsRecordSizeOf =
+      expr(sizeOfExpr(hasArgumentOfType(equalsBoundNode("Record"))));
+  auto HasCxxRecordArgs = [&](Matcher<CXXRecordDecl> RecordConstraint,
+                              BindableMatcher<Stmt> SecondArg) {
+    return allOf(argumentCountIs(3),
+                 hasArgument(0, IsStructPointer(RecordConstraint, true)),
+                 hasArgument(1, SecondArg), hasArgument(2, IsRecordSizeOf));
+  };
+  std::vector<std::string> MemSet = utils::options::parseStringList(
+      (llvm::Twine(BuiltinMemSet) + MemSetNames).str());
+  std::vector<std::string> MemCpy = utils::options::parseStringList(
+      (llvm::Twine(BuiltinMemCpy) + MemCpyNames).str());
+        std::vector<std::string> MemCmp = utils::options::parseStringList(
+      (llvm::Twine(BuiltinMemCmp) + MemCmpNames).str());
+
+  auto IsIntZero = expr(integerLiteral(equals(0)));
+
+  Finder->addMatcher(
+      callExpr(callee(namedDecl(hasAnyName(toStringRefVec(MemSet)))),
+               HasCxxRecordArgs(unless(isTriviallyDefaultConstructible()),
+                                IsIntZero))
+          .bind("lazyConstruct"),
+      this);
+  Finder->addMatcher(callExpr(callee(namedDecl(hasAnyName(toStringRefVec(MemCpy)))),
+                              HasCxxRecordArgs(unless(isTriviallyCopyable()),
+                                               IsStructPointer()))
+                         .bind("lazyCopy"),
+                     this);
+  Finder->addMatcher(
+      callExpr(callee(namedDecl(hasAnyName(toStringRefVec(MemCmp)))),
+               HasCxxRecordArgs(hasMethod(hasAnyName(EqualityComparison)),
+                                IsStructPointer()))
+          .bind("lazyCompare"),
+      this);
+}
+
+void NotTrivialTypesLibcMemoryCallsCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  if (const auto *Caller = Result.Nodes.getNodeAs<CallExpr>("lazyConstruct")) {
+    diag(Caller->getBeginLoc(), "Calling '%0' on a non trivially default "
+                                "constructible class is undefined")
+        << getName(*Caller);
+  }
+  if (const auto *Caller = Result.Nodes.getNodeAs<CallExpr>("lazyCopy")) {
+    diag(Caller->getBeginLoc(),
+         "Calling '%0' on a non trivially copyable class is undefined")
+        << getName(*Caller);
+  }
+  if (const auto *Caller = Result.Nodes.getNodeAs<CallExpr>("lazyCompare")) {
+    diag(Caller->getBeginLoc(),
+         "consider using comparison operators instead of calling '%0'")
+        << getName(*Caller);
+  }
+}
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/cert/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/cert/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/cert/CMakeLists.txt
@@ -8,6 +8,7 @@
   FloatLoopCounter.cpp
   LimitedRandomnessCheck.cpp
   MutatingCopyCheck.cpp
+  NotTrivialTypesLibcMemoryCallsCheck.cpp
   PostfixOperatorCheck.cpp
   ProperlySeededRandomGeneratorCheck.cpp
   SetLongJmpCheck.cpp
Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -24,6 +24,7 @@
 #include "FloatLoopCounter.h"
 #include "LimitedRandomnessCheck.h"
 #include "MutatingCopyCheck.h"
+#include "NotTrivialTypesLibcMemoryCallsCheck.h"
 #include "PostfixOperatorCheck.h"
 #include "ProperlySeededRandomGeneratorCheck.h"
 #include "SetLongJmpCheck.h"
@@ -70,6 +71,8 @@
         "cert-oop11-cpp");
     CheckFactories.registerCheck<bugprone::UnhandledSelfAssignmentCheck>(
         "cert-oop54-cpp");
+    CheckFactories.registerCheck<NotTrivialTypesLibcMemoryCallsCheck>(
+        "cert-oop57-cpp");
     CheckFactories.registerCheck<MutatingCopyCheck>(
         "cert-oop58-cpp");
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to