1 //===--- UndefinedMemoryManipulationCheck.cpp - clang-tidy-----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "UndefinedMemoryManipulationCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace bugprone {
19 
20 namespace {
21 AST_MATCHER(CXXRecordDecl, isNotTriviallyCopyable) {
22   // For incomplete types, assume they are TriviallyCopyable.
23   return Node.hasDefinition() ? !Node.isTriviallyCopyable() : false;
24 }
25 } // namespace
26 
27 void UndefinedMemoryManipulationCheck::registerMatchers(MatchFinder *Finder) {
28   const auto NotTriviallyCopyableObject =
29       hasType(ast_matchers::hasCanonicalType(
30           pointsTo(cxxRecordDecl(isNotTriviallyCopyable()))));
31 
32   // Check whether destination object is not TriviallyCopyable.
33   // Applicable to all three memory manipulation functions.
34   Finder->addMatcher(callExpr(callee(functionDecl(hasAnyName(
35                                   "::memset", "::memcpy", "::memmove"))),
36                               hasArgument(0, NotTriviallyCopyableObject))
37                          .bind("dest"),
38                      this);
39 
40   // Check whether source object is not TriviallyCopyable.
41   // Only applicable to memcpy() and memmove().
42   Finder->addMatcher(
43       callExpr(callee(functionDecl(hasAnyName("::memcpy", "::memmove"))),
44                hasArgument(1, NotTriviallyCopyableObject))
45           .bind("src"),
46       this);
47 }
48 
49 void UndefinedMemoryManipulationCheck::check(
50     const MatchFinder::MatchResult &Result) {
51   if (const auto *Call = Result.Nodes.getNodeAs<CallExpr>("dest")) {
52     QualType DestType = Call->getArg(0)->IgnoreImplicit()->getType();
53     if (!DestType->getPointeeType().isNull())
54       DestType = DestType->getPointeeType();
55     diag(Call->getLocStart(), "undefined behavior, destination object type %0 "
56                               "is not TriviallyCopyable")
57         << DestType;
58   }
59   if (const auto *Call = Result.Nodes.getNodeAs<CallExpr>("src")) {
60     QualType SourceType = Call->getArg(1)->IgnoreImplicit()->getType();
61     if (!SourceType->getPointeeType().isNull())
62       SourceType = SourceType->getPointeeType();
63     diag(Call->getLocStart(),
64          "undefined behavior, source object type %0 is not TriviallyCopyable")
65         << SourceType;
66   }
67 }
68 
69 } // namespace bugprone
70 } // namespace tidy
71 } // namespace clang
72