clang  6.0.0svn
NonnullGlobalConstantsChecker.cpp
Go to the documentation of this file.
1 //==- NonnullGlobalConstantsChecker.cpp ---------------------------*- C++ -*--//
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 // This checker adds an assumption that constant globals of certain types* are
11 // non-null, as otherwise they generally do not convey any useful information.
12 // The assumption is useful, as many framework use e. g. global const strings,
13 // and the analyzer might not be able to infer the global value if the
14 // definition is in a separate translation unit.
15 // The following types (and their typedef aliases) are considered to be
16 // non-null:
17 // - `char* const`
18 // - `const CFStringRef` from CoreFoundation
19 // - `NSString* const` from Foundation
20 // - `CFBooleanRef` from Foundation
21 //
22 //===----------------------------------------------------------------------===//
23 
24 #include "ClangSACheckers.h"
30 
31 using namespace clang;
32 using namespace ento;
33 
34 namespace {
35 
36 class NonnullGlobalConstantsChecker : public Checker<check::Location> {
37  mutable IdentifierInfo *NSStringII = nullptr;
38  mutable IdentifierInfo *CFStringRefII = nullptr;
39  mutable IdentifierInfo *CFBooleanRefII = nullptr;
40 
41 public:
42  NonnullGlobalConstantsChecker() {}
43 
44  void checkLocation(SVal l, bool isLoad, const Stmt *S,
45  CheckerContext &C) const;
46 
47 private:
48  void initIdentifierInfo(ASTContext &Ctx) const;
49 
50  bool isGlobalConstString(SVal V) const;
51 
52  bool isNonnullType(QualType Ty) const;
53 };
54 
55 } // namespace
56 
57 /// Lazily initialize cache for required identifier informations.
58 void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const {
59  if (NSStringII)
60  return;
61 
62  NSStringII = &Ctx.Idents.get("NSString");
63  CFStringRefII = &Ctx.Idents.get("CFStringRef");
64  CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef");
65 }
66 
67 /// Add an assumption that const string-like globals are non-null.
68 void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
69  const Stmt *S,
70  CheckerContext &C) const {
71  initIdentifierInfo(C.getASTContext());
72  if (!isLoad || !location.isValid())
73  return;
74 
76  SVal V = State->getSVal(location.castAs<Loc>());
77 
78  if (isGlobalConstString(location)) {
80 
81  if (Constr) {
82 
83  // Assume that the variable is non-null.
84  ProgramStateRef OutputState = State->assume(*Constr, true);
85  C.addTransition(OutputState);
86  }
87  }
88 }
89 
90 /// \param V loaded lvalue.
91 /// \return whether {@code val} is a string-like const global.
92 bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
94  if (!RegionVal)
95  return false;
96  auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion());
97  if (!Region)
98  return false;
99  const VarDecl *Decl = Region->getDecl();
100 
101  if (!Decl->hasGlobalStorage())
102  return false;
103 
104  QualType Ty = Decl->getType();
105  bool HasConst = Ty.isConstQualified();
106  if (isNonnullType(Ty) && HasConst)
107  return true;
108 
109  // Look through the typedefs.
110  while (auto *T = dyn_cast<TypedefType>(Ty)) {
111  Ty = T->getDecl()->getUnderlyingType();
112 
113  // It is sufficient for any intermediate typedef
114  // to be classified const.
115  HasConst = HasConst || Ty.isConstQualified();
116  if (isNonnullType(Ty) && HasConst)
117  return true;
118  }
119  return false;
120 }
121 
122 /// \return whether {@code type} is extremely unlikely to be null
123 bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
124 
125  if (Ty->isPointerType() && Ty->getPointeeType()->isCharType())
126  return true;
127 
128  if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) {
129  return T->getInterfaceDecl() &&
130  T->getInterfaceDecl()->getIdentifier() == NSStringII;
131  } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
132  IdentifierInfo* II = T->getDecl()->getIdentifier();
133  return II == CFStringRefII || II == CFBooleanRefII;
134  }
135  return false;
136 }
137 
138 void ento::registerNonnullGlobalConstantsChecker(CheckerManager &Mgr) {
139  Mgr.registerChecker<NonnullGlobalConstantsChecker>();
140 }
A (possibly-)qualified type.
Definition: Type.h:653
Stmt - This represents one statement.
Definition: Stmt.h:66
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:456
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:806
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
LineState State
bool isCharType() const
Definition: Type.cpp:1750
IdentifierTable & Idents
Definition: ASTContext.h:537
const FunctionProtoType * T
bool isValid() const
Definition: SVals.h:137
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:100
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:5779
CHECKER * registerChecker()
Used to register checkers.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition: Decl.h:1067
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
Dataflow Directional Tag Classes.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:92
const ProgramStateRef & getState() const
bool isPointerType() const
Definition: Type.h:5944
QualType getType() const
Definition: Decl.h:638