Skip to content

Commit d993e76

Browse files
committed
[clang-tidy] Function names configurable for cppcoreguidelines-nomalloc - checker
Summary: Hello everybody, this is an incremental patch for the NoMalloc-Checker I wrote. It allows to configure the memory-management functions, that are checked, This might be helpful for a code base with custom functions in use, or non-standard functionality, like posix_memalign. Reviewers: aaron.ballman, hokein, alexfh Reviewed By: aaron.ballman, alexfh Subscribers: sbenza, nemanjai, JDevlieghere Tags: #clang-tools-extra Patch by Jonas Toth! Differential Revision: https://reviews.llvm.org/D28239 llvm-svn: 296734
1 parent b8ebcb5 commit d993e76

File tree

6 files changed

+149
-11
lines changed

6 files changed

+149
-11
lines changed

clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,63 @@
88
//===----------------------------------------------------------------------===//
99

1010
#include "NoMallocCheck.h"
11+
#include "../utils/Matchers.h"
12+
#include "../utils/OptionsUtils.h"
1113
#include "clang/AST/ASTContext.h"
1214
#include "clang/ASTMatchers/ASTMatchFinder.h"
13-
#include <iostream>
15+
#include <algorithm>
1416
#include <string>
17+
#include <vector>
1518

1619
using namespace clang::ast_matchers;
20+
using namespace clang::ast_matchers::internal;
1721

1822
namespace clang {
1923
namespace tidy {
2024
namespace cppcoreguidelines {
2125

26+
namespace {
27+
Matcher<FunctionDecl> hasAnyListedName(const std::string &FunctionNames) {
28+
const std::vector<std::string> NameList =
29+
utils::options::parseStringList(FunctionNames);
30+
return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
31+
}
32+
}
33+
34+
void NoMallocCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
35+
Options.store(Opts, "Allocations", AllocList);
36+
Options.store(Opts, "Reallocations", ReallocList);
37+
Options.store(Opts, "Deallocations", DeallocList);
38+
}
39+
2240
void NoMallocCheck::registerMatchers(MatchFinder *Finder) {
2341
// C-style memory management is only problematic in C++.
2442
if (!getLangOpts().CPlusPlus)
2543
return;
2644

2745
// Registering malloc, will suggest RAII.
28-
Finder->addMatcher(
29-
callExpr(callee(functionDecl(hasAnyName("::malloc", "::calloc"))))
30-
.bind("aquisition"),
31-
this);
46+
Finder->addMatcher(callExpr(callee(functionDecl(hasAnyListedName(AllocList))))
47+
.bind("allocation"),
48+
this);
3249

3350
// Registering realloc calls, suggest std::vector or std::string.
3451
Finder->addMatcher(
35-
callExpr(callee(functionDecl(hasName("::realloc")))).bind("realloc"),
52+
callExpr(callee(functionDecl(hasAnyListedName(ReallocList))))
53+
.bind("realloc"),
3654
this);
3755

3856
// Registering free calls, will suggest RAII instead.
3957
Finder->addMatcher(
40-
callExpr(callee(functionDecl(hasName("::free")))).bind("free"), this);
58+
callExpr(callee(functionDecl(hasAnyListedName(DeallocList))))
59+
.bind("free"),
60+
this);
4161
}
4262

4363
void NoMallocCheck::check(const MatchFinder::MatchResult &Result) {
4464
const CallExpr *Call = nullptr;
4565
StringRef Recommendation;
4666

47-
if ((Call = Result.Nodes.getNodeAs<CallExpr>("aquisition")))
67+
if ((Call = Result.Nodes.getNodeAs<CallExpr>("allocation")))
4868
Recommendation = "consider a container or a smart pointer";
4969
else if ((Call = Result.Nodes.getNodeAs<CallExpr>("realloc")))
5070
Recommendation = "consider std::vector or std::string";

clang-tools-extra/clang-tidy/cppcoreguidelines/NoMallocCheck.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,32 @@ namespace cppcoreguidelines {
2727
/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-no-malloc.html
2828
class NoMallocCheck : public ClangTidyCheck {
2929
public:
30+
/// Construct Checker and read in configuration for function names.
3031
NoMallocCheck(StringRef Name, ClangTidyContext *Context)
31-
: ClangTidyCheck(Name, Context) {}
32+
: ClangTidyCheck(Name, Context),
33+
AllocList(Options.get("Allocations", "::malloc;::calloc")),
34+
ReallocList(Options.get("Reallocations", "::realloc")),
35+
DeallocList(Options.get("Deallocations", "::free")) {}
36+
37+
/// Make configuration of checker discoverable.
38+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
3239

3340
/// Registering for malloc, calloc, realloc and free calls.
3441
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
3542

3643
/// Checks matched function calls and gives suggestion to modernize the code.
3744
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
45+
46+
private:
47+
/// Semicolon-seperated list of fully qualified names of memory allocation
48+
/// functions the check warns about. Defaults to `::malloc;::calloc`.
49+
const std::string AllocList;
50+
/// Semicolon-seperated list of fully qualified names of memory reallocation
51+
/// functions the check warns about. Defaults to `::realloc`.
52+
const std::string ReallocList;
53+
/// Semicolon-seperated list of fully qualified names of memory deallocation
54+
/// functions the check warns about. Defaults to `::free`.
55+
const std::string DeallocList;
3856
};
3957

4058
} // namespace cppcoreguidelines

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ Improvements to clang-tidy
6262

6363
Finds modification of the ``std`` or ``posix`` namespace.
6464

65+
- Improved `cppcoreguidelines-no-malloc
66+
<http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-no-malloc.html>`_ check
67+
68+
Allow custom memory management functions to be considered as well.
69+
6570
- New `readability-misleading-indentation
6671
<http://clang.llvm.org/extra/clang-tidy/checks/readability-misleading-indentation.html>`_ check
6772

clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ cppcoreguidelines-no-malloc
66
This check handles C-Style memory management using ``malloc()``, ``realloc()``,
77
``calloc()`` and ``free()``. It warns about its use and tries to suggest the use
88
of an appropriate RAII object.
9-
See `C++ Core Guidelines
10-
<https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-mallocfree>`.
9+
Furthermore, it can be configured to check against a user-specified list of functions
10+
that are used for memory management (e.g. ``posix_memalign()``).
11+
See `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-mallocfree>`_.
1112

1213
There is no attempt made to provide fix-it hints, since manual resource
1314
management isn't easily transformed automatically into RAII.
@@ -25,3 +26,21 @@ management isn't easily transformed automatically into RAII.
2526
// Rather use a smartpointer or stack variable.
2627
struct some_struct* s = (struct some_struct*) malloc(sizeof(struct some_struct));
2728

29+
Options
30+
-------
31+
32+
.. option:: Allocations
33+
34+
Semicolon-separated list of fully qualified names of memory allocation functions.
35+
Defaults to ``::malloc;::calloc``.
36+
37+
.. option:: Deallocations
38+
39+
Semicolon-separated list of fully qualified names of memory allocation functions.
40+
Defaults to ``::free``.
41+
42+
.. option:: Reallocations
43+
44+
Semicolon-separated list of fully qualified names of memory allocation functions.
45+
Defaults to ``::realloc``.
46+
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
2+
// RUN: -config='{CheckOptions: \
3+
// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc;::align_malloc;::calloc"},\
4+
// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: "::realloc;::align_realloc"},\
5+
// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: "::free;::align_free"}]}' \
6+
// RUN: --
7+
8+
using size_t = __SIZE_TYPE__;
9+
10+
void *malloc(size_t size);
11+
void *align_malloc(size_t size, unsigned short aligmnent);
12+
void *calloc(size_t num, size_t size);
13+
void *realloc(void *ptr, size_t size);
14+
void *align_realloc(void *ptr, size_t size, unsigned short alignment);
15+
void free(void *ptr);
16+
void *align_free(void *ptr);
17+
18+
void malloced_array() {
19+
int *array0 = (int *)malloc(sizeof(int) * 20);
20+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
21+
22+
int *zeroed = (int *)calloc(20, sizeof(int));
23+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
24+
25+
int *aligned = (int *)align_malloc(20 * sizeof(int), 16);
26+
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
27+
28+
// reallocation memory, std::vector shall be used
29+
char *realloced = (char *)realloc(array0, 50 * sizeof(int));
30+
// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
31+
32+
char *align_realloced = (char *)align_realloc(aligned, 50 * sizeof(int), 16);
33+
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: do not manage memory manually; consider std::vector or std::string [cppcoreguidelines-no-malloc]
34+
35+
// freeing memory the bad way
36+
free(realloced);
37+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
38+
39+
align_free(align_realloced);
40+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
41+
42+
// check if a call to malloc as function argument is found as well
43+
free(malloc(20));
44+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
45+
// CHECK-MESSAGES: :[[@LINE-2]]:8: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
46+
}
47+
48+
/// newing an array is still not good, but not relevant to this checker
49+
void newed_array() {
50+
int *new_array = new int[10]; // OK(1)
51+
}
52+
53+
void arbitrary_call() {
54+
// we dont want every function to raise the warning even if malloc is in the name
55+
malloced_array(); // OK(2)
56+
57+
// completly unrelated function call to malloc
58+
newed_array(); // OK(3)
59+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %check_clang_tidy %s cppcoreguidelines-no-malloc %t \
2+
// RUN: -config='{CheckOptions: \
3+
// RUN: [{key: cppcoreguidelines-no-malloc.Allocations, value: "::malloc"},\
4+
// RUN: {key: cppcoreguidelines-no-malloc.Reallocations, value: ""},\
5+
// RUN: {key: cppcoreguidelines-no-malloc.Deallocations, value: ""}]}' \
6+
// RUN: --
7+
8+
// Just ensure, the check will not crash, when no functions shall be checked.
9+
10+
using size_t = __SIZE_TYPE__;
11+
12+
void *malloc(size_t size);
13+
14+
void malloced_array() {
15+
int *array0 = (int *)malloc(sizeof(int) * 20);
16+
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not manage memory manually; consider a container or a smart pointer [cppcoreguidelines-no-malloc]
17+
}

0 commit comments

Comments
 (0)