Index: clang-tidy/cppcoreguidelines/CMakeLists.txt =================================================================== --- clang-tidy/cppcoreguidelines/CMakeLists.txt +++ clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyCppCoreGuidelinesModule CppCoreGuidelinesTidyModule.cpp InterfacesGlobalInitCheck.cpp + NoMallocCheck.cpp ProBoundsArrayToPointerDecayCheck.cpp ProBoundsConstantArrayIndexCheck.cpp ProBoundsPointerArithmeticCheck.cpp Index: clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp =================================================================== --- clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -12,6 +12,7 @@ #include "../ClangTidyModuleRegistry.h" #include "../misc/UnconventionalAssignOperatorCheck.h" #include "InterfacesGlobalInitCheck.h" +#include "NoMallocCheck.h" #include "ProBoundsArrayToPointerDecayCheck.h" #include "ProBoundsConstantArrayIndexCheck.h" #include "ProBoundsPointerArithmeticCheck.h" @@ -35,6 +36,7 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "cppcoreguidelines-interfaces-global-init"); + CheckFactories.registerCheck("cppcoreguidelines-no-malloc"); CheckFactories.registerCheck( "cppcoreguidelines-pro-bounds-array-to-pointer-decay"); CheckFactories.registerCheck( Index: clang-tidy/cppcoreguidelines/NoMallocCheck.h =================================================================== --- /dev/null +++ clang-tidy/cppcoreguidelines/NoMallocCheck.h @@ -0,0 +1,44 @@ +//===--- NoMallocCheck.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_NO_MALLOC_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NO_MALLOC_H + +#include "../ClangTidy.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +/// This checker is concerned with C-style memory management and suggest modern +/// alternatives to it. +/// The check is only enabled in C++. For analyzing malloc calls see Clang +/// Static Analyzer - unix.Malloc. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-no-malloc.html +class NoMallocCheck : public ClangTidyCheck { +public: + NoMallocCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + /// Registering for malloc, calloc, realloc and free calls. + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + + /// Checks matched function calls and gives suggestion to modernize the code. + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NO_MALLOC_H Index: clang-tidy/cppcoreguidelines/NoMallocCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/cppcoreguidelines/NoMallocCheck.cpp @@ -0,0 +1,62 @@ +//===--- NoMallocCheck.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 "NoMallocCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include +#include + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +void NoMallocCheck::registerMatchers(MatchFinder *Finder) { + // C-style memory management is only problematic in C++. + if (!getLangOpts().CPlusPlus) + return; + + // Registering malloc, will suggest RAII. + Finder->addMatcher( + callExpr(callee(functionDecl(hasAnyName("::malloc", "::calloc")))) + .bind("aquisition"), + this); + + // Registering realloc calls, suggest std::vector or std::string. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::realloc")))).bind("realloc"), + this); + + // Registering free calls, will suggest RAII instead. + Finder->addMatcher( + callExpr(callee(functionDecl(hasName("::free")))).bind("free"), this); +} + +void NoMallocCheck::check(const MatchFinder::MatchResult &Result) { + const CallExpr *Call = nullptr; + StringRef Recommendation; + + if ((Call = Result.Nodes.getNodeAs("aquisition"))) + Recommendation = "consider a container or a smart pointer"; + else if ((Call = Result.Nodes.getNodeAs("realloc"))) + Recommendation = "consider std::vector or std::string"; + else if ((Call = Result.Nodes.getNodeAs("free"))) + Recommendation = "use RAII"; + + assert(Call && "Unhandled binding in the Matcher"); + + diag(Call->getLocStart(), "do not manage memory manually; %0") + << Recommendation << SourceRange(Call->getLocStart(), Call->getLocEnd()); +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -81,6 +81,10 @@ Warns if an object is used after it has been moved, without an intervening reinitialization. +- New `cppcoreguidelines-no-malloc + `_ check + warns if C-style memory management is used and suggests the use of RAII. + - `modernize-make-unique `_ and `modernize-make-shared Index: docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst @@ -0,0 +1,27 @@ +.. title:: clang-tidy - cppcoreguidelines-no-malloc + +cppcoreguidelines-no-malloc +=========================== + +This check handles C-Style memory management using ``malloc()``, ``realloc()``, +``calloc()`` and ``free()``. It warns about its use and tries to suggest the use +of an appropriate RAII object. +See `C++ Core Guidelines + + +There is no attempt made to provide fixit hints, since manual resource management isn't +easily transformed automatically into RAII. + +.. code-block:: c++ + + // Warns each of the following lines. + // Containers like std::vector or std::string should be used. + char* some_string = (char*) malloc(sizeof(char) * 20); + char* some_string = (char*) realloc(sizeof(char) * 30); + free(some_string); + + int* int_array = (int*) calloc(30, sizeof(int)); + + // Rather use a smartpointer or stack variable. + struct some_struct* s = (struct some_struct*) malloc(sizeof(struct some_struct)); + Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -22,6 +22,7 @@ cert-msc50-cpp cert-oop11-cpp (redirects to misc-move-constructor-init) cppcoreguidelines-interfaces-global-init + cppcoreguidelines-no-malloc cppcoreguidelines-pro-bounds-array-to-pointer-decay cppcoreguidelines-pro-bounds-constant-array-index cppcoreguidelines-pro-bounds-pointer-arithmetic Index: test/clang-tidy/cppcoreguidelines-no-malloc.cpp =================================================================== --- /dev/null +++ test/clang-tidy/cppcoreguidelines-no-malloc.cpp @@ -0,0 +1,42 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t + +using size_t = unsigned long; + +void *malloc(size_t size); +void *calloc(size_t num, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +void malloced_array() { + int *array0 = (int *)malloc(sizeof(int) * 20); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc] + + int *zeroed = (int *)calloc(20, sizeof(int)); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc] + + // reallocation memory, std::vector shall be used + char *realloced = (char *)realloc(array0, 50 * sizeof(int)); + // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc] + + // freeing memory the bad way + free(realloced); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc] + + // check if a call to malloc as function argument is found as well + free(malloc(20)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc] + // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc] +} + +/// newing an array is still not good, but not relevant to this checker +void newed_array() { + int *new_array = new int[10]; // OK(1) +} + +void arbitrary_call() { + // we dont want every function to raise the warning even if malloc is in the name + malloced_array(); // OK(2) + + // completly unrelated function call to malloc + newed_array(); // OK(3) +}