clang  19.0.0git
ObjCContainersASTChecker.cpp
Go to the documentation of this file.
1 //== ObjCContainersASTChecker.cpp - CoreFoundation containers API *- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // An AST checker that looks for common pitfalls when using 'CFArray',
10 // 'CFDictionary', 'CFSet' APIs.
11 //
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/StmtVisitor.h"
16 #include "clang/Basic/TargetInfo.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class WalkAST : public StmtVisitor<WalkAST> {
28  BugReporter &BR;
29  const CheckerBase *Checker;
31  ASTContext &ASTC;
32  uint64_t PtrWidth;
33 
34  /// Check if the type has pointer size (very conservative).
35  inline bool isPointerSize(const Type *T) {
36  if (!T)
37  return true;
38  if (T->isIncompleteType())
39  return true;
40  return (ASTC.getTypeSize(T) == PtrWidth);
41  }
42 
43  /// Check if the type is a pointer/array to pointer sized values.
44  inline bool hasPointerToPointerSizedType(const Expr *E) {
45  QualType T = E->getType();
46 
47  // The type could be either a pointer or array.
48  const Type *TP = T.getTypePtr();
49  QualType PointeeT = TP->getPointeeType();
50  if (!PointeeT.isNull()) {
51  // If the type is a pointer to an array, check the size of the array
52  // elements. To avoid false positives coming from assumption that the
53  // values x and &x are equal when x is an array.
54  if (const Type *TElem = PointeeT->getArrayElementTypeNoTypeQual())
55  if (isPointerSize(TElem))
56  return true;
57 
58  // Else, check the pointee size.
59  return isPointerSize(PointeeT.getTypePtr());
60  }
61 
62  if (const Type *TElem = TP->getArrayElementTypeNoTypeQual())
63  return isPointerSize(TElem);
64 
65  // The type must be an array/pointer type.
66 
67  // This could be a null constant, which is allowed.
68  return static_cast<bool>(
70  }
71 
72 public:
73  WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
74  : BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
75  PtrWidth(ASTC.getTargetInfo().getPointerWidth(LangAS::Default)) {}
76 
77  // Statement visitor methods.
78  void VisitChildren(Stmt *S);
79  void VisitStmt(Stmt *S) { VisitChildren(S); }
80  void VisitCallExpr(CallExpr *CE);
81 };
82 } // end anonymous namespace
83 
84 static StringRef getCalleeName(CallExpr *CE) {
85  const FunctionDecl *FD = CE->getDirectCallee();
86  if (!FD)
87  return StringRef();
88 
89  IdentifierInfo *II = FD->getIdentifier();
90  if (!II) // if no identifier, not a simple C function
91  return StringRef();
92 
93  return II->getName();
94 }
95 
96 void WalkAST::VisitCallExpr(CallExpr *CE) {
97  StringRef Name = getCalleeName(CE);
98  if (Name.empty())
99  return;
100 
101  const Expr *Arg = nullptr;
102  unsigned ArgNum;
103 
104  if (Name == "CFArrayCreate" || Name == "CFSetCreate") {
105  if (CE->getNumArgs() != 4)
106  return;
107  ArgNum = 1;
108  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
109  if (hasPointerToPointerSizedType(Arg))
110  return;
111  } else if (Name == "CFDictionaryCreate") {
112  if (CE->getNumArgs() != 6)
113  return;
114  // Check first argument.
115  ArgNum = 1;
116  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
117  if (hasPointerToPointerSizedType(Arg)) {
118  // Check second argument.
119  ArgNum = 2;
120  Arg = CE->getArg(ArgNum)->IgnoreParenCasts();
121  if (hasPointerToPointerSizedType(Arg))
122  // Both are good, return.
123  return;
124  }
125  }
126 
127  if (Arg) {
128  assert(ArgNum == 1 || ArgNum == 2);
129 
130  SmallString<64> BufName;
131  llvm::raw_svector_ostream OsName(BufName);
132  OsName << " Invalid use of '" << Name << "'" ;
133 
134  SmallString<256> Buf;
135  llvm::raw_svector_ostream Os(Buf);
136  // Use "second" and "third" since users will expect 1-based indexing
137  // for parameter names when mentioned in prose.
138  Os << " The " << ((ArgNum == 1) ? "second" : "third") << " argument to '"
139  << Name << "' must be a C array of pointer-sized values, not '"
140  << Arg->getType() << "'";
141 
142  PathDiagnosticLocation CELoc =
144  BR.EmitBasicReport(AC->getDecl(), Checker, OsName.str(),
145  categories::CoreFoundationObjectiveC, Os.str(), CELoc,
146  Arg->getSourceRange());
147  }
148 
149  // Recurse and check children.
150  VisitChildren(CE);
151 }
152 
153 void WalkAST::VisitChildren(Stmt *S) {
154  for (Stmt *Child : S->children())
155  if (Child)
156  Visit(Child);
157 }
158 
159 namespace {
160 class ObjCContainersASTChecker : public Checker<check::ASTCodeBody> {
161 public:
162 
163  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
164  BugReporter &BR) const {
165  WalkAST walker(BR, this, Mgr.getAnalysisDeclContext(D));
166  walker.Visit(D->getBody());
167  }
168 };
169 }
170 
171 void ento::registerObjCContainersASTChecker(CheckerManager &mgr) {
172  mgr.registerChecker<ObjCContainersASTChecker>();
173 }
174 
175 bool ento::shouldRegisterObjCContainersASTChecker(const CheckerManager &mgr) {
176  return true;
177 }
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static StringRef getCalleeName(CallExpr *CE)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2355
AnalysisDeclContext contains the context data for the function, method or block under analysis.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2872
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3050
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3063
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3042
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1077
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:3116
@ NPC_ValueDependentIsNull
Specifies that a value-dependent expression of integral or dependent type should be considered a null...
Definition: Expr.h:821
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to a Null pointer constant.
Definition: Expr.cpp:3980
QualType getType() const
Definition: Expr.h:142
Represents a function declaration or definition.
Definition: Decl.h:1972
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
A (possibly-)qualified type.
Definition: Type.h:940
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1007
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:7371
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:185
Stmt - This represents one statement.
Definition: Stmt.h:84
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
The base class of the type hierarchy.
Definition: Type.h:1813
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition: Type.cpp:427
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:705
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2361
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:585
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
const SourceManager & getSourceManager()
Definition: BugReporter.h:623
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Defines the clang::TargetInfo interface.
const char *const CoreFoundationObjectiveC
The JSON file list parser is used to communicate input to InstallAPI.
LangAS
Defines the address space values used by the address space qualifier of QualType.
Definition: AddressSpaces.h:25
const FunctionProtoType * T
unsigned long uint64_t