baloghadamsoftware created this revision.
Herald added subscribers: mgorny, srhines.

A possible error is to write ``malloc(strlen(s+1))`` instead of 
``malloc(strlen(s)+1)``. Unfortunately the former is also valid syntactically, 
but allocates less memory by two bytes (if ``s`` is at least one character 
long, undefined behavior otherwise) which may result in overflow cases. This 
check detects such cases and also suggests the fix for them.


https://reviews.llvm.org/D39121

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.cpp
  clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  docs/clang-tidy/checks/misc-misplaced-operator-in-strlen-in-alloc.rst
  test/clang-tidy/misc-misplaced-operator-in-strlen-in-alloc.cpp

Index: test/clang-tidy/misc-misplaced-operator-in-strlen-in-alloc.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/misc-misplaced-operator-in-strlen-in-alloc.cpp
@@ -0,0 +1,26 @@
+// RUN: %check_clang_tidy %s misc-misplaced-operator-in-strlen-in-alloc %t
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+void *realloc(void *, size_t);
+
+size_t strlen(const char*);
+
+void bad_malloc(char *name) {
+  char *new_name = (char*) malloc(strlen(name + 1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: Binary operator + 1 is inside strlen
+  // CHECK-FIXES: {{^  char \*new_name = \(char\*\) malloc\(}}strlen(name) + 1{{\);$}}
+}
+
+void bad_calloc(char *name) {
+  char *new_names = (char*) calloc(2, strlen(name + 1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: Binary operator + 1 is inside strlen
+  // CHECK-FIXES: {{^  char \*new_names = \(char\*\) calloc\(2, }}strlen(name) + 1{{\);$}}
+}
+
+void bad_realloc(char * old_name, char *name) {
+  char *new_name = (char*) realloc(old_name, strlen(name + 1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: Binary operator + 1 is inside strlen
+  // CHECK-FIXES: {{^  char \*new_name = \(char\*\) realloc\(old_name, }}strlen(name) + 1{{\);$}}
+}
Index: docs/clang-tidy/checks/misc-misplaced-operator-in-strlen-in-alloc.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/misc-misplaced-operator-in-strlen-in-alloc.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - misc-misplaced-operator-in-strlen-in-alloc
+
+misc-misplaced-operator-in-strlen-in-alloc
+==========================================
+
+Finds cases a value is added to or subtracted from the string in the parameter
+of ``strlen()`` method instead of to the result and use its return value as an
+argument of a memory allocation function (``malloc()``, ``calloc()``,
+``realloc()``).
+
+Example code:
+
+.. code-block:: c
+
+    void bad_malloc(char *str) {
+      char *c = (char*) malloc(strlen(str + 1));
+    }
+
+
+The suggested fix is to add value to the return value of ``strlen()`` and not
+to its argument. In the example above the fix would be
+
+.. code-block:: c
+
+      char *c = (char*) malloc(strlen(str) + 1);
+
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -7,9 +7,9 @@
    android-cloexec-accept
    android-cloexec-accept4
    android-cloexec-creat
+   android-cloexec-dup
    android-cloexec-epoll-create
    android-cloexec-epoll-create1
-   android-cloexec-dup
    android-cloexec-fopen
    android-cloexec-inotify-init
    android-cloexec-inotify-init1
@@ -38,7 +38,7 @@
    cert-msc30-c (redirects to cert-msc50-cpp) <cert-msc30-c>
    cert-msc50-cpp
    cert-oop11-cpp (redirects to misc-move-constructor-init) <cert-oop11-cpp>
-   cppcoreguidelines-c-copy-assignment-signature
+   cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) <cppcoreguidelines-c-copy-assignment-signature>
    cppcoreguidelines-interfaces-global-init
    cppcoreguidelines-no-malloc
    cppcoreguidelines-owning-memory
@@ -76,8 +76,8 @@
    hicpp-explicit-conversions (redirects to google-explicit-constructor) <hicpp-explicit-conversions>
    hicpp-function-size (redirects to readability-function-size) <hicpp-function-size>
    hicpp-invalid-access-moved (redirects to misc-use-after-move) <hicpp-invalid-access-moved>
-   hicpp-move-const-arg (redirects to misc-move-const-arg) <hicpp-move-const-arg>
    hicpp-member-init (redirects to cppcoreguidelines-pro-type-member-init) <hicpp-member-init>
+   hicpp-move-const-arg (redirects to misc-move-const-arg) <hicpp-move-const-arg>
    hicpp-named-parameter (redirects to readability-named-parameter) <hicpp-named-parameter>
    hicpp-new-delete-operators (redirects to misc-new-delete-overloads) <hicpp-new-delete-operators>
    hicpp-no-array-decay (redirects to cppcoreguidelines-pro-bounds-array-to-pointer-decay) <hicpp-no-array-decay>
@@ -95,7 +95,7 @@
    hicpp-use-noexcept (redirects to modernize-use-noexcept) <hicpp-use-noexcept>
    hicpp-use-nullptr (redirects to modernize-use-nullptr) <hicpp-use-nullptr>
    hicpp-use-override (redirects to modernize-use-override) <hicpp-use-override>
-   hicpp-vararg (redirects to cppcoreguidelines-pro-type-varg) <hicpp-vararg>
+   hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) <hicpp-vararg>
    llvm-header-guard
    llvm-include-order
    llvm-namespace-comment
@@ -115,6 +115,7 @@
    misc-macro-parentheses
    misc-macro-repeated-side-effects
    misc-misplaced-const
+   misc-misplaced-operator-in-strlen-in-alloc
    misc-misplaced-widening-cast
    misc-move-const-arg
    misc-move-constructor-init
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -57,6 +57,14 @@
 Improvements to clang-tidy
 --------------------------
 
+- New `misc-misplaced-operator-in-strlen-in-alloc
+  <http://clang.llvm.org/extra/clang-tidy/checks/misc-misplaced-operator-in-strlen-in-alloc.html>`_ check
+
+  Finds cases a value is added to or subtracted from the string in the parameter
+  of ``strlen()`` method instead of to the result and use its return value as an
+  argument of a memory allocation function (``malloc()``, ``calloc()``,
+  ``realloc()``). The check also suggests the appropriate fix.
+
 - Renamed checks to use correct term "implicit conversion" instead of "implicit
   cast" and modified messages and option names accordingly:
 
Index: clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.h
@@ -0,0 +1,35 @@
+//===--- MisplacedOperatorInStrlenInAllocCheck.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_MISC_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
+
+#include "../ClangTidy.h"
+
+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-misplaced-operator-in-strlen-in-alloc.html
+class MisplacedOperatorInStrlenInAllocCheck : public ClangTidyCheck {
+public:
+  MisplacedOperatorInStrlenInAllocCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MISPLACED_OPERATOR_IN_STRLEN_IN_ALLOC_H
Index: clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/misc/MisplacedOperatorInStrlenInAllocCheck.cpp
@@ -0,0 +1,68 @@
+//===--- MisplacedOperatorInStrlenInAllocCheck.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 "MisplacedOperatorInStrlenInAllocCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+void MisplacedOperatorInStrlenInAllocCheck::registerMatchers(
+    MatchFinder *Finder) {
+  const auto BadUse =
+      callExpr(
+          callee(functionDecl(hasName("strlen"))),
+          hasAnyArgument(ignoringParenImpCasts(
+              binaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")))
+                  .bind("BinOp"))))
+          .bind("StrLen");
+  Finder->addMatcher(
+      callExpr(callee(functionDecl(hasName("malloc"))),
+               hasArgument(0, anyOf(hasDescendant(BadUse), BadUse)))
+          .bind("Alloc"),
+      this);
+  Finder->addMatcher(
+      callExpr(
+          callee(functionDecl(anyOf(hasName("calloc"), hasName("realloc")))),
+          hasArgument(1, anyOf(hasDescendant(BadUse), BadUse)))
+          .bind("Alloc"),
+      this);
+}
+
+void MisplacedOperatorInStrlenInAllocCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  // FIXME: Add callback implementation.
+  const auto *Alloc = Result.Nodes.getNodeAs<CallExpr>("Alloc");
+  const auto *StrLen = Result.Nodes.getNodeAs<CallExpr>("StrLen");
+  const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("BinOp");
+
+  const std::string LHSText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(BinOp->getLHS()->getSourceRange()),
+      *Result.SourceManager, getLangOpts());
+  const std::string RHSText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(BinOp->getRHS()->getSourceRange()),
+      *Result.SourceManager, getLangOpts());
+
+  auto Hint = FixItHint::CreateReplacement(
+      StrLen->getSourceRange(),
+      "strlen(" + LHSText + ")" +
+          ((BinOp->getOpcode() == BO_Add) ? " + " : " - ") + RHSText);
+
+  diag(Alloc->getLocStart(), "Binary operator %0 %1 is inside strlen")
+      << ((BinOp->getOpcode() == BO_Add) ? "+" : "-") << BinOp->getRHS()
+      << Hint;
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -25,6 +25,7 @@
 #include "MacroParenthesesCheck.h"
 #include "MacroRepeatedSideEffectsCheck.h"
 #include "MisplacedConstCheck.h"
+#include "MisplacedOperatorInStrlenInAllocCheck.h"
 #include "MisplacedWideningCastCheck.h"
 #include "MoveConstantArgumentCheck.h"
 #include "MoveConstructorInitCheck.h"
@@ -72,6 +73,8 @@
     CheckFactories.registerCheck<LambdaFunctionNameCheck>(
         "misc-lambda-function-name");
     CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const");
+    CheckFactories.registerCheck<MisplacedOperatorInStrlenInAllocCheck>(
+        "misc-misplaced-operator-in-strlen-in-alloc");
     CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
         "misc-unconventional-assign-operator");
     CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -6,6 +6,7 @@
   ForwardingReferenceOverloadCheck.cpp
   LambdaFunctionNameCheck.cpp
   MisplacedConstCheck.cpp
+  MisplacedOperatorInStrlenInAllocCheck.cpp
   UnconventionalAssignOperatorCheck.cpp
   BoolPointerImplicitConversionCheck.cpp
   DanglingHandleCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to