ktomi996 created this revision.
ktomi996 added reviewers: aaron.ballman, alexfh, hokein, njames93.
ktomi996 added a project: clang-tools-extra.
Herald added subscribers: cfe-commits, mgorny.
Herald added a project: clang.
ktomi996 requested review of this revision.

This checker guards against using some vulnerable C functions which are 
mentioned in MSC24-C in obsolescent functions table.
The checker warns only if __STDC_LIB_EXT1__ macro is defined and the value of 
__STDC_WANT_LIB_EXT1__ macro is 1 in this case it suggests the corresponding 
functions from Annex K instead the vulnerable function.
https://wiki.sei.cmu.edu/confluence/display/c/MSC24-C.+Do+not+use+deprecated+or+obsolescent+functions


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D91000

Files:
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/clang-tidy/cert/CMakeLists.txt
  clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.cpp
  clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.h
  clang-tools-extra/clang-tidy/misc/CMakeLists.txt
  clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.cpp
  clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-obsolescent-functions.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/cert-obsolescent-functions.cpp

Index: clang-tools-extra/test/clang-tidy/cert-obsolescent-functions.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/cert-obsolescent-functions.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s cert-obsolescent-functions %t --
+
+#define __STDC_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1
+void * memmove(void *, void *, unsigned int);
+void f1(const char *in) {
+  int i = 1;
+  int j = 2;
+  memmove(&i, &j, sizeof(int));
+    // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Unsafe function memmove used. Safe memmove_s can be used instead. [cert-obsolescent-functions]
+}
+
+
+void f2(const char *in) {
+    void * (*func_ptr)(void *, void *, unsigned int) = memmove;
+// CHECK-MESSAGES: :[[@LINE-1]]:56: warning: Unsafe function memmove used. Safe memmove_s can be used instead. [cert-obsolescent-functions]
+}
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
@@ -100,6 +100,7 @@
    cert-msc32-c (redirects to cert-msc51-cpp) <cert-msc32-c>
    cert-msc50-cpp
    cert-msc51-cpp
+   cert-obsolescent-functions
    cert-oop11-cpp (redirects to performance-move-constructor-init) <cert-oop11-cpp>
    cert-oop54-cpp (redirects to bugprone-unhandled-self-assignment) <cert-oop54-cpp>
    cppcoreguidelines-avoid-c-arrays (redirects to modernize-avoid-c-arrays) <cppcoreguidelines-avoid-c-arrays>
Index: clang-tools-extra/docs/clang-tidy/checks/cert-obsolescent-functions.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cert-obsolescent-functions.rst
@@ -0,0 +1,23 @@
+..title::clang-tidy-cert-obsolescent-functions
+
+cert-obsolescent-functions
+==========================
+    
+Guards against using some unsafe function calls and function pointers which initialized with unsafe functions if __STDC_LIB_EXT1__ macro is defined and the value of __STDC_WANT_LIB_EXT1__ is 1. The usage of following functions are checked : bsearch,
+    fprintf, fscanf, fwprintf, fwscanf, getenv, gmtime, localtime, mbsrtowcs,
+    mbstowcs, memcpy, memmove, printf, qsort, setbuf, snprintf, sprintf, sscanf,
+    strcat, strcpy, strerror, strncat, strncpy, strtok, swprintf, swscanf,
+    vfprintf, vfscanf, vfwprintf, vfwscanf, vprintf, vscanf vsnprintf, vspr,
+    wcscpy, wcsncat, wcsncpy wcsrtombs, wcstok, wcstombs, wctomb, wmemcpy,
+    wmemmove, wprintf, wscanf,
+    strlen
+
+This is a CERT security rule:
+https://wiki.sei.cmu.edu/confluence/display/c/MSC24-C.+Do+not+use+deprecated+or+obsolescent+functions
+      Example :
+      .code-block::
+        #define __STDC_WANT_LIB_EXT1__ 1
+        int i = 2;
+        int j = 3;
+        memmove(&i, &j, sizeof(int)); // diagnosed if __STDC_LIB_EXT1__ is defined in a
+                                    // header, memmove_s usage is suggested instead.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -194,6 +194,13 @@
   against self-assignment either by checking self-assignment explicitly or
   using the copy-and-swap or the copy-and-move method.
 
+- New :doc:`cert-obsolescent-functions
+  <clang-tidy/checks/cert-obsolescent-functions>` check.
+
+  Guards against using some unsafe function calls and function pointers which
+  initialized with unsafe functions if some macros defined.
+
+
 - New :doc:`fuchsia-default-arguments-calls
   <clang-tidy/checks/fuchsia-default-arguments-calls>` check.
 
Index: clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.h
@@ -0,0 +1,147 @@
+//===--- CountFunctionsCheck.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_MISC_COUNTFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_COUNTFUNCTIONSCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include <map>
+#include <vector>
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-count-functions.html
+class CountFunctionsCheck : public ClangTidyCheck {
+private:
+    std::vector<std::string> names;
+    std::map<std::string, int> counts;
+public:
+  CountFunctionsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {
+             names = {"bsearch",
+                "fprintf",
+
+                "fscanf",
+
+                "fwprintf",
+
+                "fwscanf",
+
+                "getenv"
+
+                "gmtime",
+
+                "localtime",
+
+                "mbsrtowcs",
+
+                "mbstowcs",
+
+                "memcpy",
+
+                "memmove",
+
+                "printf",
+
+                "qsort",
+
+                "setbuf",
+
+                "snprintf",
+
+                "sprintf",
+
+                "sscanf",
+
+                "strcat",
+
+                "strcpy",
+
+                "strerror",
+
+                "strncat",
+
+                "strncpy",
+
+                "strtok",
+
+                "swprintf",
+
+                "swscanf",
+
+                "vfprintf",
+
+                "vfscanf",
+
+                "vfwprintf",
+
+                "vfwscanf",
+
+                "vprintf",
+
+                "vscanf",
+
+                "vsnprintf",
+
+                "vsprintf",
+
+                "vsscanf",
+
+                "vswprintf",
+
+                "vswscanf",
+
+                "vwprintf",
+
+                "vwscanf",
+
+                "wcrtomb"
+
+                "wcscat",
+
+                "wcscpy",
+
+                "wcsncat",
+
+                "wcsncpy",
+
+                "wcsrtombs",
+
+                "wcstok",
+
+                "wcstombs",
+
+                "wctomb",
+
+                "wmemcpy",
+
+                "wmemmove",
+
+                "wprintf",
+
+                "wscanf"
+
+            };
+     for(int i = 0; i < names.size(); ++i) {
+         counts[names[i]] = 0;
+    }
+      }
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  ~CountFunctionsCheck();
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_COUNTFUNCTIONSCHECK_H
Index: clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/misc/CountFunctionsCheck.cpp
@@ -0,0 +1,55 @@
+//===--- CountFunctionsCheck.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 "CountFunctionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <fstream>
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void CountFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+  // FIXME: Add matchers.
+    for(int i = 0; i < names.size(); ++i) {
+        Finder -> addMatcher(callExpr(callee(functionDecl(hasName("::" + names[i])))).bind(names[i]), this);
+        Finder -> addMatcher(varDecl(
+                            hasInitializer(
+                              ignoringImpCasts(
+                                declRefExpr(to(functionDecl(
+                                  hasName("::" + names[i]))))))).bind(names[i] + "p"), this);
+    }
+}
+
+void CountFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
+  // FIXME: Add callback implementation.
+  for(int i = 0; i < names.size(); ++i) {
+      const CallExpr * sth = Result.Nodes.getNodeAs<CallExpr>(names[i]);
+      if(sth != 0) {
+          ++counts[names[i]];
+      }
+      const VarDecl * sth2 = Result.Nodes.getNodeAs<VarDecl>(names[i]+"p");
+      if(sth2 != 0) {
+          ++counts[names[i]];
+      }
+  }
+}
+
+CountFunctionsCheck::~CountFunctionsCheck() {
+    std::ofstream myfile;
+    myfile.open("counts.txt");
+    for(int i = 0; i < names.size(); ++i) {
+        myfile << names[i] << ": " << counts[names[i]] << std::endl;
+    }
+    myfile.close();
+}
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(LLVM_LINK_COMPONENTS support)
 
 add_clang_library(clangTidyMiscModule
+  CountFunctionsCheck.cpp
   DefinitionsInHeadersCheck.cpp
   MiscTidyModule.cpp
   MisplacedConstCheck.cpp
Index: clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.h
@@ -0,0 +1,36 @@
+//===--- ObsolescentFunctionsCheck.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_OBSOLESCENTFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_OBSOLESCENTFUNCTIONSCHECK_H
+
+#include "../ClangTidyCheck.h"
+namespace clang {
+namespace tidy {
+namespace cert {
+
+/// Guards against using some unsafe function calls and function pointers which initialized with unsafe functions if some macros defined.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-obsolescent-functions.html
+class ObsolescentFunctionsCheck : public ClangTidyCheck {
+public:
+  ObsolescentFunctionsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  const std::pair<bool, bool> UsingAnnexK();
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpandedPP) override;
+};
+
+} // namespace cert
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_OBSOLESCENTFUNCTIONSCHECK_H
Index: clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cert/ObsolescentFunctionsCheck.cpp
@@ -0,0 +1,103 @@
+//===--- ObsolescentFunctionsCheck.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 "ObsolescentFunctionsCheck.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cert {
+
+namespace {
+static Preprocessor *PP;
+}
+
+void ObsolescentFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+  const auto CheckedFunctions = functionDecl(hasAnyName(
+      "::bsearch", "::fprintf", "::fscanf", "::fwprintf", "::fwscanf",
+      "::getenv", "::gmtime", "::localtime", "::mbsrtowcs", "::mbstowcs",
+      "::memcpy", "::memmove", "::printf", "::qsort", "::setbuf", "::snprintf",
+      "::sprintf", "::sscanf", "::strcat", "::strcpy", "::strerror",
+      "::strncat", "::strncpy", "::strtok", "::swprintf", "::swscanf",
+      "::vfprintf", "::vfscanf", "vfwprintf", "vfwscanf", "vprintf", "::vscanf",
+      "::vsnprintf", "::vsprintf", "::vsscanf", "::vswprintf", "::vswcanf",
+      "::wcrtomb", "::wcscat", "::wcscpy", "::wcsncat", "::wcsncpy",
+      "::wcsrtombs", "::wcstok", "::wcstombs", "::wctomb", "::wmemcpy",
+      "::wmemmove", "::wprintf", "::wscanf", "::strlen"));
+  Finder->addMatcher(
+      callExpr(callee(CheckedFunctions.bind("fn"))).bind("callexpr"), this);
+
+  Finder->addMatcher(varDecl(hasInitializer(ignoringImpCasts(declRefExpr(
+                                 to(CheckedFunctions.bind("fnp"))))))
+                         .bind("fp"),
+                     this);
+}
+
+void ObsolescentFunctionsCheck::registerPPCallbacks(
+    const SourceManager &SM, Preprocessor *Preproc,
+    Preprocessor *ModuleExpandedPP) {
+  PP = Preproc;
+}
+
+const std::pair<bool, bool> ObsolescentFunctionsCheck::UsingAnnexK() {
+  bool AnnexKIsAvailable;
+  bool AnnexKIsWanted;
+  if (!PP->isMacroDefined("__STDC_LIB_EXT1__")) {
+    AnnexKIsAvailable = false;
+  } else {
+    AnnexKIsAvailable = true;
+  }
+  const IdentifierInfo *Id = PP->getIdentifierInfo("__STDC_WANT_LIB_EXT1__");
+  AnnexKIsWanted = false;
+  if (!Id) {
+    AnnexKIsWanted = false;
+  } else {
+    const auto *MI = PP->getMacroInfo(Id);
+    const auto &T = MI->tokens().back();
+    StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
+    llvm::APInt IntValue;
+    ValueStr.getAsInteger(10, IntValue);
+    Optional<bool> AreSafeFunctionsWanted;
+    AreSafeFunctionsWanted = IntValue.getZExtValue();
+    if (AreSafeFunctionsWanted.hasValue()) {
+      AnnexKIsWanted = AreSafeFunctionsWanted.getValue();
+    }
+  }
+  return std::make_pair(AnnexKIsAvailable, AnnexKIsWanted);
+}
+
+void ObsolescentFunctionsCheck::check(const MatchFinder::MatchResult &Result) {
+  std::pair<bool, bool> AnnexKUsage = UsingAnnexK();
+  bool AnnexKIsAvailable = std::get<0>(AnnexKUsage);
+  bool AnnexKIsWanted = std::get<1>(AnnexKUsage);
+  if (!AnnexKIsWanted || !AnnexKIsAvailable) {
+    return;
+  }
+  if (const auto *Function = Result.Nodes.getNodeAs<CallExpr>("callexpr")) {
+    const FunctionDecl *FD = Result.Nodes.getNodeAs<FunctionDecl>("fn");
+    const NamedDecl *NFD = dyn_cast<NamedDecl>(FD);
+    std::string FunctionName = NFD->getNameAsString();
+    diag(Function->getExprLoc(), "Unsafe function " + FunctionName + " used. " +
+                                     "Safe " + FunctionName +
+                                     "_s can be used instead.");
+  }
+  if (const auto *FunctionPointer = Result.Nodes.getNodeAs<VarDecl>("fp")) {
+    if (const FunctionDecl *FD = Result.Nodes.getNodeAs<FunctionDecl>("fnp")) {
+      const NamedDecl *NFD = dyn_cast<NamedDecl>(FD);
+      std::string FunctionName = NFD->getNameAsString();
+      diag(FunctionPointer->getEndLoc(),
+           "Unsafe function " + FunctionName + " used. " + "Safe " +
+               FunctionName + "_s can be used instead.");
+    }
+  }
+}
+} // 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
@@ -6,6 +6,7 @@
   DontModifyStdNamespaceCheck.cpp
   FloatLoopCounter.cpp
   LimitedRandomnessCheck.cpp
+  ObsolescentFunctionsCheck.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
@@ -21,6 +21,7 @@
 #include "DontModifyStdNamespaceCheck.h"
 #include "FloatLoopCounter.h"
 #include "LimitedRandomnessCheck.h"
+#include "ObsolescentFunctionsCheck.h"
 #include "PostfixOperatorCheck.h"
 #include "ProperlySeededRandomGeneratorCheck.h"
 #include "SetLongJmpCheck.h"
@@ -79,6 +80,8 @@
     // ERR
     CheckFactories.registerCheck<StrToNumCheck>("cert-err34-c");
     // MSC
+    CheckFactories.registerCheck<ObsolescentFunctionsCheck>(
+        "cert-obsolescent-functions");
     CheckFactories.registerCheck<LimitedRandomnessCheck>("cert-msc30-c");
     CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
         "cert-msc32-c");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D91000: MSC24-C Obso... Koller Tamás via Phabricator via cfe-commits

Reply via email to