This is an archive of the discontinued LLVM Phabricator instance.

[Clang-tidy] check for malloc, realloc and free calls
ClosedPublic

Authored by JonasToth on Oct 31 2016, 2:45 PM.

Details

Summary

This checker flags the use of C-style memory management functionality and notes about modern alternatives.
In an earlier revision it tried to autofix some kind of patterns, but that was a bad idea. Since memory management can be so widespread in a program, manual updating is most likely necessary.
Maybe for special cases, there could be later additions to this basic checker.

This is the first checker I wrote and I never did something with clang (only compiling programs). So whenever I missed conventions or did plain retarded stuff, feel free to point it out! I am willing to fix them and write a better checker.

I hope the patch does work, I never did this either. On a testapply in my repository it did, but I am pretty unconfident in my patching skills :)

Diff Detail

Repository
rL LLVM

Event Timeline

JonasToth updated this revision to Diff 76484.Oct 31 2016, 2:45 PM
JonasToth retitled this revision from to Clang-Tidy check for malloc, realloc and free calls.
JonasToth updated this object.
JonasToth added a reviewer: Restricted Project.
JonasToth added a project: Restricted Project.
Eugene.Zelenko retitled this revision from Clang-Tidy check for malloc, realloc and free calls to [Clang-tidy] check for malloc, realloc and free calls.Oct 31 2016, 3:03 PM
Eugene.Zelenko edited reviewers, added: alexfh, aaron.ballman, hokein; removed: Restricted Project.
Eugene.Zelenko set the repository for this revision to rL LLVM.
Eugene.Zelenko added a subscriber: Prazek.
JonasToth updated this object.Oct 31 2016, 3:06 PM

Please mention this check in docs/ReleaseNotes.rst (in alphabetical order).

Please run Clang-format over test case.

clang-tidy/modernize/NoMallocCheck.cpp
148 ↗(On Diff #76484)

Please don't use auto when type could not be easily deduced.

docs/clang-tidy/checks/modernize-no-malloc.rst
6 ↗(On Diff #76484)

Please add documentation.

test/clang-tidy/modernize-no-malloc.cpp
3 ↗(On Diff #76484)

Non needed extra empty line.

5 ↗(On Diff #76484)

Non needed extra empty line.

64 ↗(On Diff #76484)

Non needed extra empty lines.

78 ↗(On Diff #76484)

Non needed extra empty line.

JonasToth updated this revision to Diff 76608.Nov 1 2016, 11:24 AM
JonasToth removed rL LLVM as the repository for this revision.

I added documentation, mentioned nomalloccheck in the release notes and reformated the testcase.

Furthermore i realized that there is a problem with the code transformation in the following case:

malloc(sizeof(struct S) * count);
// becomes
new struct S[count];

This is invalid, struct must be removed. I did not figure it out fast, but i added a bug note in the documentation and will take care of this.

JonasToth set the repository for this revision to rL LLVM.Nov 1 2016, 11:29 AM

If this is part of C++ Core Guidelines, will be good idea to add alias in cppcoreguidelines group.

Will be good idea to add calloc support, at least when default constructors are present.

docs/ReleaseNotes.rst
87

Stile -> style.

I think operator `new` will be more correct wording. Same in documentation.

docs/clang-tidy/checks/modernize-no-malloc.rst
9 ↗(On Diff #76608)

Please highlight malloc, free with ``. Same below.

46 ↗(On Diff #76608)

Stile -> stile.

47 ↗(On Diff #76608)

Will be good idea to link to relevant guideline.

JonasToth marked 6 inline comments as done.Nov 1 2016, 11:33 AM

I adjusted the first comments from Eugene

JonasToth added inline comments.Nov 1 2016, 11:37 AM
docs/clang-tidy/checks/modernize-no-malloc.rst
47 ↗(On Diff #76608)

I have a link in the intro:
See `CppCoreGuidlines
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#r-resource-management`
This is the very general section. Since I recomment std::make_unique<type[]> and so on, i think its a good lecture.

Section [R.10] is for malloc specific, i will add this one. What about the reference in the diagnostics? I have [R.10] in one, but the others didnt seem to fit.

Eugene.Zelenko added inline comments.Nov 1 2016, 11:41 AM
docs/clang-tidy/checks/modernize-no-malloc.rst
47 ↗(On Diff #76608)

Sorry, I overlook link. Please use C++ Core Guidelines in text (two places) for consistency with other cppcoreguidelines checks documentation.

JonasToth updated this revision to Diff 76613.Nov 1 2016, 12:21 PM

Fixing the issues pointed out by eugene, only documentation related.

JonasToth marked 6 inline comments as done.Nov 1 2016, 12:23 PM

adjusted the issues in a new patch

JonasToth updated this revision to Diff 76615.Nov 1 2016, 12:24 PM
JonasToth removed rL LLVM as the repository for this revision.

i forgot release not adjustment, sry :/

hokein edited edge metadata.Nov 7 2016, 11:01 AM

@JonasToth, welcome to llvm community and thanks for your contribution.

Could you please read [LLVM code style](http://llvm.org/docs/CodingStandards.html) and make your code align with the code style (specially in LLVM we use Camel Case for variable/function name)? And you can use clang-format to help you automatically handle other code style issues.

clang-tidy/modernize/NoMallocCheck.cpp
19 ↗(On Diff #76615)

The comment doesn't give any information here. It is fine to delete it.

35 ↗(On Diff #76615)

Looks like you forgot to delete this comment.

84 ↗(On Diff #76615)

const auto* size_of

87 ↗(On Diff #76615)

Since you use early return in if statement.
You can remove the else here. The same below.

109 ↗(On Diff #76615)

The code can be simplified to if (const auto* CastMatch = Result.Nodes.getNodeAs<CStyleCastExpr>("c_cast");). The same below.

149 ↗(On Diff #76615)

Seems to me that this is not a valid C++ statement?

164 ↗(On Diff #76615)

no else either.

171 ↗(On Diff #76615)

no else.

212 ↗(On Diff #76615)

It can be written as if (infer_sizeof_type(arg->getLHS(), type)) {. The same below.

251 ↗(On Diff #76615)

no else.

clang-tidy/modernize/NoMallocCheck.h
19 ↗(On Diff #76615)

I think the check should be holding in cppcoreguidelines module.

docs/clang-tidy/checks/modernize-no-malloc.rst
45 ↗(On Diff #76615)

As you mentioned in the paragraph, only replacing new and leaving free behind is an incomplete. which will mess up new and free usage. Can't we also replace free to delete?

52 ↗(On Diff #76615)

Can we ignore these types in the check? otherwise, it will make the check give incorrect warnings on these types.

test/clang-tidy/modernize-no-malloc.cpp
3 ↗(On Diff #76615)

We don't use standard library header directly in lint tests. You can declare malloc, free function by yourself.

iam fixing the style issues at the moment. since these are some, it will take a little :)

what is your thought on removing the fixing? this will make this check more simple, but more robust as well.

maybe i can add options to the check, that will enable some fixes. but this would then be a further enhancement to the
basic check that just warns about the c style memory management.

clang-tidy/modernize/NoMallocCheck.cpp
149 ↗(On Diff #76615)

why not? it compiles and seemed to work quite well :)

docs/clang-tidy/checks/modernize-no-malloc.rst
45 ↗(On Diff #76615)

iam thinking about to remove the fixing in general.
the problem with replacing free with delete is that there is no consistent information if its an array or a single object.
i dont know if you can keep track of the variable names, but aliasing, deleting in another source file and so on will interfere with it.

i think its a good idea to just warn about all cstyle memory management and point to cppcoreguidelines for information how to change it.

52 ↗(On Diff #76615)

as said above. i think the fixing wasnt the best idea.

JonasToth marked 10 inline comments as done.Nov 8 2016, 10:11 AM

adjusted test

alexfh requested changes to this revision.Nov 8 2016, 4:45 PM
alexfh edited edge metadata.
alexfh added inline comments.
clang-tidy/modernize/NoMallocCheck.cpp
149 ↗(On Diff #76615)

Please don't use alternative tokens. It's not common for LLVM code. Same goes for trigraphs, if you wonder ;)

This revision now requires changes to proceed.Nov 8 2016, 4:45 PM
alexfh added a comment.Nov 8 2016, 4:48 PM

Jonas, thank you for the patch!

Please review and internalize http://llvm.org/docs/CodingStandards.html. It will help you and others save a lot of time on code reviews.

docs/ReleaseNotes.rst
87

s/C style/C-style/

JonasToth added inline comments.Nov 9 2016, 9:54 AM
clang-tidy/modernize/NoMallocCheck.cpp
149 ↗(On Diff #76615)

alright! change is done :)

JonasToth updated this revision to Diff 77379.Nov 9 2016, 10:58 AM
JonasToth edited edge metadata.
JonasToth set the repository for this revision to rL LLVM.

i fixed every part i could find that did not comply with the coding standard. still there might be issues with it, because iam not fluid in them.

furthermore i think it might be a good idea to remove the fixit hints, since it seems to be too error prone. what do you think?

JonasToth marked 4 inline comments as done.Nov 9 2016, 11:11 AM
aaron.ballman added inline comments.Nov 10 2016, 7:54 AM
clang-tidy/modernize/NoMallocCheck.cpp
44–46 ↗(On Diff #77379)

You can remove this kind of comment; it doesn't add clarity.

51 ↗(On Diff #77379)

I would roll this into countToString(), since it's short and only used once.

64 ↗(On Diff #77379)

I would roll this into inferSizeofType(); it's a one-liner.

71 ↗(On Diff #77379)

Should be const auto *.

112 ↗(On Diff #77379)

s/infere/infer; also, I would use a full stop rather than an exclamation point.

120 ↗(On Diff #77379)

Can remove the empty whitespace.

144 ↗(On Diff #77379)

I don't think this is safe to assume, because hasDescendant() traverses farther down the AST than you might expect. You should add a test case like:

void *foo(void *);

void f() {
  (char *)foo(malloc(0));
}

I think that this will match your matcher, but should not be handled here.

145 ↗(On Diff #77379)

Unlike comments, diagnostics are not meant to be grammatically correct. They should not start with a capital letter (or have terminating punctuation). This comment applies elsewhere as well.

Why is the cast not needed any more?

157–159 ↗(On Diff #77379)

I am not certain the value of this diagnostic. In C, the cast is not required (as you correctly handle), but in C++, the cast is either required (ill-formed if missing because the types do not match), or is not required because the destination type is void *. Either way, this diagnostic does not help because it's either duplicating a diagnostic from the frontend or it's a false-positive.

163 ↗(On Diff #77379)

Please use auto * (with const, if possible).

167 ↗(On Diff #77379)

You should elide the braces (here and elsewhere for single-statement if blocks).

179 ↗(On Diff #77379)

Why would this be shady? Consider: malloc(NumCharacters + 1), which is going to be quite common. Alternatively, malloc(1 << X);.

210 ↗(On Diff #77379)

No need for the variable, you can inline the expression into the if clause.

228 ↗(On Diff #77379)

This diagnostic does not help the user to figure out what's wrong with their code or how to fix it.

aaron.ballman added inline comments.Nov 10 2016, 7:54 AM
clang-tidy/modernize/NoMallocCheck.cpp
22 ↗(On Diff #77379)

Here, and elsewhere, all comments should be grammatically correct (capitalization and punctuation). Look for missing full stops at the end of a sentence, and make sure the sentence starts with a capital letter.

27 ↗(On Diff #77379)

You should not register the AST matchers unless in C++ mode (I don't think the check makes sense for C).

JonasToth updated this revision to Diff 78624.Nov 19 2016, 1:52 AM
JonasToth edited edge metadata.

Iam sorry if this is not so great, but i think i wanted to much with the automatic fixing.
As pointed out in the Code Review, there a issues with the automatic fixing and it most likely wont be of any value for real project. I tested it on a closed source project (70k lines) and it was terrible :D

The checker is now way simpler, just warning about malloc, calloc, realloc and free. Suggesting RAII, Containers or Smartpointers in a note. The diagnostics is now way shorter, and i think easier to work with.
I moved the check into cppcoreguidelines as well. Sry for the wasted time on the first revisions, but i think this one is a better check now.

Special cases like C-strings could be added later, and automatic fixing could be used later. But i think i want a little more experience with the Checker and writing a clang-tidy check first, before i start sth like that.

alexfh requested changes to this revision.Nov 30 2016, 8:19 AM
alexfh edited edge metadata.

Jonas, I suppose, reviewers are waiting until you address all outstanding comments (and mark them "Done") before the next round of review.

clang-tidy/modernize/NoMallocCheck.cpp
145 ↗(On Diff #77379)

"diagnostics are not meant to be grammatically correct" might be too strong ;) They are not supposed to be full sentences (no leading capitalization or trailing punctuation), but otherwise they should be grammatically correct ;)

This revision now requires changes to proceed.Nov 30 2016, 8:19 AM
JonasToth marked an inline comment as done.Nov 30 2016, 8:25 AM
JonasToth marked 20 inline comments as done.Nov 30 2016, 8:29 AM

I did mark all comments as done.
Most issues and codelines dont exist anymore, since the checker is now way simpler (just flagging c memorymanagement functions) and giving a note what could be used otherwise.

JonasToth marked 2 inline comments as done.Nov 30 2016, 8:33 AM
JonasToth updated this object.Nov 30 2016, 8:35 AM
JonasToth edited edge metadata.
alexfh added inline comments.Dec 1 2016, 7:05 AM
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
68–70

A note is used when there's a need to point to a different source location. There's not much sense in just splitting out a part of a warning to a note on the same location.

clang-tidy/modernize/NoMallocCheck.cpp
145 ↗(On Diff #77379)

This hasn't been addressed as far as I can see.

JonasToth added inline comments.Dec 1 2016, 8:09 AM
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
68–70

should i add the suggestion to the warning or remove it completly?

alexfh added inline comments.Dec 1 2016, 9:08 AM
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
68–70

The suggestion is fine, just merge it with the warning. Please also make sure the text is consistent with the other cppcoreguidelines checks (I mean the parts in the square brackets, I'm not sure if other checks follow the same style).

JonasToth updated this revision to Diff 79926.Dec 1 2016, 9:28 AM
JonasToth edited edge metadata.

Update the diagnostics, only one warning is produced containing the suggestion, no notes anymore.

Furthermore there is an update in 2 comments.

JonasToth marked 3 inline comments as done.Dec 1 2016, 9:29 AM

adjusted the diagnostics, i also removed the reference to the specific part of the cppcoreguidelines, making it consistent with other checkers.

JonasToth marked an inline comment as done.Dec 12 2016, 2:52 AM
alexfh requested changes to this revision.Dec 12 2016, 8:58 AM
alexfh edited edge metadata.
alexfh added inline comments.
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
55

The handle.* methods now just add more bulk and bring no benefit. With a single statement in each function they might as well be inlined and the checkmethod would be still quite compact:

CallExpr Call = nullptr;
StringRef Recommendation;
if ((Call = Result.Nodes.getNodeAs<CallExpr>("aquisition")))
  Recommendation = "consider a container or smartpointer";
else if ((Call = ...))
  ...;

assert(Call && "Unhandled binding in the matcher);

diag(Call->getLocStart(),
     "do not allocate memory manually; %0")
  << Recommendation
  << SourceRange(...);
57

"smart pointer" is two words.

58

Please use parentheses instead of curly braces for constructor calls (SourceRange(x, y)), it's more common in LLVM code.

This revision now requires changes to proceed.Dec 12 2016, 8:58 AM
JonasToth marked 3 inline comments as done.Dec 12 2016, 10:08 AM

removed the function calls, a little doc tidy as well

JonasToth updated this revision to Diff 81103.Dec 12 2016, 10:10 AM
JonasToth edited edge metadata.

fixes last review comments from alex

alexfh requested changes to this revision.Dec 12 2016, 11:20 PM
alexfh edited edge metadata.

One important thing is missing. Please run this check on a large enough codebase (LLVM + Clang is a good choice for testing most of kinds of checks usually) and include a summary of results in the patch description. The most important things are: clang-tidy doesn't crash, results (or if there are too many, then a sufficiently large random sample - say, 100) look good on manual inspection.

clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
49

nit: a smart pointer (an article is missing).

50

Please remove empty lines before else

This revision now requires changes to proceed.Dec 12 2016, 11:20 PM
JonasToth updated this revision to Diff 81193.Dec 13 2016, 1:23 AM
JonasToth edited edge metadata.
JonasToth marked 2 inline comments as done.

last fixes in the code, from alex

I did run clang-tidy with $(./run-clang-tidy.py -checks=-*,cppcoreguidelines-no-malloc). The resulting output is in the appended file.
Since all warnings came from header files (llvms custom containers?) there are always the same warnings for all source files.
Every function (calloc, malloc, realloc and free) was seen, i hope the output is sufficient.

Whats not nice is, that there is no underlining (in test neither), but i could not find out what is wrong, since i supply a SourceRange in the diag()-call.

malcolm.parsons added inline comments.
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
30

C memory management functions are also present in the std namespace.

docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
11

Do you mean #r10-avoid-malloc-and-free?

27

Missing variable.

JonasToth marked an inline comment as done.Dec 13 2016, 2:25 AM
JonasToth added inline comments.
docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
11

yes, but i think the wider view is more appropriate. RAII is a general strategy, and not specific to malloc etc.

27

that slipped through. i fix it.

JonasToth marked an inline comment as done.Dec 13 2016, 2:26 AM
JonasToth added inline comments.
clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
30

in the clang codebase, std::malloc got catched as well. see the tidy_output_no_malloc.txt in one of my previous comments.

JonasToth updated this revision to Diff 81204.Dec 13 2016, 2:28 AM
JonasToth edited edge metadata.

fix missing variable in doc

JonasToth marked an inline comment as done.Dec 13 2016, 2:29 AM
docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
5

A few = missing.

11

This checker is specific to R.10.
The documentation for all the other cppcoreguidelines checks mention which rule they're enforcing.

JonasToth updated this revision to Diff 81208.Dec 13 2016, 3:02 AM

adjusted doc.

JonasToth marked 4 inline comments as done.Dec 13 2016, 3:02 AM
JonasToth added inline comments.
docs/clang-tidy/checks/cppcoreguidelines-no-malloc.rst
11

alright. i will adjust.

JonasToth marked 2 inline comments as done.Dec 13 2016, 3:03 AM
alexfh accepted this revision.Dec 13 2016, 6:18 AM
alexfh edited edge metadata.

LG, but please wait until Malcolm

Whats not nice is, that there is no underlining (in test neither), but i could not find out what is wrong,
since i supply a SourceRange in the diag()-call.

Please leave the range anyway. I suspect clang-tidy doesn't handle ranges in diagnostics correctly, but it's easier to fix this, if there is an example already.

This revision is now accepted and ready to land.Dec 13 2016, 6:18 AM

Hit "submit" too early.

LG, but please wait until Malcolm is happy with the change as well.

alexfh removed a subscriber: malcolm.parsons.
malcolm.parsons accepted this revision.Dec 13 2016, 6:51 AM
malcolm.parsons edited edge metadata.

LGTM.

JonasToth marked 2 inline comments as done.Dec 13 2016, 7:30 AM

Jonas, do you need someone to commit the patch for you?

tbh. i dont know anything how the clang workflow works :)

do i need to ask someone to commit, or what be my next step?

Jonas, do you need someone to commit the patch for you?

i think so, yes. can i trigger somehow automatically, that this will go into the code base somehow?

alexfh closed this revision.Dec 13 2016, 9:12 AM

Committed in r289546.

rnk added a subscriber: rnk.Dec 13 2016, 12:35 PM

nit: All of the new files had UTF-8 BOMs, which I don't think we usually add.

test/clang-tidy/cppcoreguidelines-no-malloc.cpp
3

This test did not pass on 32-bit Windows. I will change it to:

using size_t = __SIZE_TYPE__;

I tried this check on my company's codebase.
It misses cases where malloc is used through a function pointer.
Should clang-tidy warn about making a function pointer to these functions?

I tried this check on my company's codebase.
It misses cases where malloc is used through a function pointer.
Should clang-tidy warn about making a function pointer to these functions?

Sounds like a good idea to me. I can't really imagine a scenario where you'd want to enable this check and not be warned about it.

alright, i will try to get the functionpointers as well.
what do you think about configuration of the allocating functions? e.g. for aligned memory you must use OS-specific allocation functions.
should the check catch custom allocation functions as well?

is there a way to make a list of allocation, reallocation, deallocation functions that the check shall look for (+aliases to these)?

JonasToth marked an inline comment as done.Dec 14 2016, 2:34 AM

what do you think about configuration of the allocating functions? e.g. for aligned memory you must use OS-specific allocation functions.
should the check catch custom allocation functions as well?

Sounds like a good idea to me.

what do you think about configuration of the allocating functions? e.g. for aligned memory you must use OS-specific allocation functions.
should the check catch custom allocation functions as well?

Sounds like a good idea to me.

I think this check should also warn about strdup(), strndup() and wcsdup().

kimgr added a subscriber: kimgr.Dec 27 2016, 3:42 AM

Minor spelling nits inline

clang-tidy/cppcoreguidelines/NoMallocCheck.cpp
30

Spelling nit: acquisition

But I wonder if there's a simpler word you can use for this, e.g. "alloc"

47

"aquisition" as above