Index: clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h =================================================================== --- clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h +++ clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.h @@ -16,9 +16,9 @@ namespace tidy { namespace bugprone { -/// Finds cases where ``1`` is added to the string in the argument to a function -/// in the ``strlen()`` family instead of the result and value is used as an -/// argument to a memory allocation function. +/// Finds cases where ``1`` is added to the string in the parameter of a +/// function in the ``strlen()`` family instead of to the result and use its +/// return value as an argument of a memory allocation function. /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.html Index: clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp =================================================================== --- clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp +++ clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp @@ -48,26 +48,32 @@ const auto Alloc1Func = functionDecl(anyOf(hasName("::calloc"), hasName("std::calloc"), hasName("::realloc"), hasName("std::realloc"))); - Finder->addMatcher( callExpr(callee(Alloc0Func), hasArgument(0, BadArg)).bind("Alloc"), this); Finder->addMatcher( callExpr(callee(Alloc1Func), hasArgument(1, BadArg)).bind("Alloc"), this); + Finder->addMatcher( + cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); } void MisplacedOperatorInStrlenInAllocCheck::check( const MatchFinder::MatchResult &Result) { - const auto *Alloc = Result.Nodes.getNodeAs("Alloc"); + const Expr *Alloc = Result.Nodes.getNodeAs("Alloc"); + if (!Alloc) + Alloc = Result.Nodes.getNodeAs("Alloc"); + assert(Alloc && "Matched node bound by 'Alloc' shoud be either 'CallExpr'" + " or 'CXXNewExpr'"); + const auto *StrLen = Result.Nodes.getNodeAs("StrLen"); const auto *BinOp = Result.Nodes.getNodeAs("BinOp"); const StringRef StrLenText = Lexer::getSourceText( CharSourceRange::getTokenRange(StrLen->getSourceRange()), *Result.SourceManager, getLangOpts()); - const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find('(') + 1); const StringRef Arg0Text = Lexer::getSourceText( CharSourceRange::getTokenRange(StrLen->getArg(0)->getSourceRange()), *Result.SourceManager, getLangOpts()); + const StringRef StrLenBegin = StrLenText.substr(0, StrLenText.find(Arg0Text)); const StringRef StrLenEnd = StrLenText.substr( StrLenText.find(Arg0Text) + Arg0Text.size(), StrLenText.size()); Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -60,11 +60,11 @@ - New `bugprone-misplaced-operator-in-strlen-in-alloc `_ check - Finds cases where ``1`` is added to the string in the argument to - ``strlen()``, ``strnlen()``, ``strnlen_s()``, ``wcslen()``, ``wcsnlen()``, and - ``wcsnlen_s()`` instead of the result and the value is used as an argument to - a memory allocation function (``malloc()``, ``calloc()``, ``realloc()``, - ``alloca()``). + Finds cases where ``1`` is added to the string in the parameter of + ``strlen()``, ``strnlen()``, ``strnlen_s()``, ``wcslen()``, ``wcsnlen()`` and + ``wcsnlen_s()`` functions instead of to the result and use its return value as + an argument of a memory allocation function (``malloc()``, ``calloc()``, + ``realloc()``, ``alloca()``) or the ``new[]`` operator in `C++`. - Renamed checks to use correct term "implicit conversion" instead of "implicit cast" and modified messages and option names accordingly: Index: docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst =================================================================== --- docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst +++ docs/clang-tidy/checks/bugprone-misplaced-operator-in-strlen-in-alloc.rst @@ -3,15 +3,16 @@ bugprone-misplaced-operator-in-strlen-in-alloc ============================================== -Finds cases where ``1`` is added to the string in the argument to ``strlen()``, -``strnlen()``, ``strnlen_s()``, ``wcslen()``, ``wcsnlen()``, and ``wcsnlen_s()`` -instead of the result and the value is used as an argument to a memory -allocation function (``malloc()``, ``calloc()``, ``realloc()``, ``alloca()``). -Cases where ``1`` is added both to the parameter and the result of the -``strlen()``-like function are ignored, as are cases where the whole addition is -surrounded by extra parentheses. +Finds cases where ``1`` is added to the string in the parameter of ``strlen()``, +``strnlen()``, ``strnlen_s()``, ``wcslen()``, ``wcsnlen()`` and ``wcsnlen_s()`` +functions instead of to the result and use its return value as an argument of a +memory allocation function (``malloc()``, ``calloc()``, ``realloc()``, +``alloca()``) or the ``new[]`` operator in `C++`. Cases where ``1`` is added +both to the parameter and the result of the ``strlen()``-like function are +ignored, as are cases where the whole addition is surrounded by extra +parentheses. -Example code: +`C` example code: .. code-block:: c @@ -28,7 +29,25 @@ char *c = (char*) malloc(strlen(str) + 1); -Example for silencing the diagnostic: +`C++` example code: + +.. code-block:: c++ + + void bad_new(char *str) { + char *c = new char[strlen(str + 1)]; + } + + +As in the `C` code with the ``malloc()`` function, the suggested fix is to +add ``1`` to the return value of ``strlen()`` and not to its argument. In the +example above the fix would be + +.. code-block:: c++ + + char *c = new char[strlen(str) + 1]; + + +Example for silencing the bug report: .. code-block:: c Index: test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp =================================================================== --- test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp +++ test/clang-tidy/bugprone-misplaced-operator-in-strlen-in-alloc.cpp @@ -29,3 +29,29 @@ char *new_name = (char*) std::malloc(non_std::strlen(name + 1)); // Ignore functions of the strlen family in custom namespaces } + +void bad_new_strlen(char *name) { + char *new_name = new char[std::strlen(name + 1)]; + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: Addition operator is applied to the argument of strlen + // CHECK-FIXES: {{^ char \*new_name = new char\[}}std::strlen(name) + 1{{\];$}} +} + +void good_new_strlen(char *name) { + char *new_name = new char[std::strlen(name) + 1]; + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:20: warning: Addition operator is applied to the argument of strlen +} + +class C { + char c; +public: + static void *operator new[](std::size_t count) { + return ::operator new(count); + } +}; + +void bad_custom_new_strlen(char *name) { + C *new_name = new C[std::strlen(name + 1)]; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Addition operator is applied to the argument of strlen + // CHECK-FIXES: {{^ C \*new_name = new C\[}}std::strlen(name) + 1{{\];$}} +} +