xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 03dff12197d15161ffc9ec7afeb9501551d6119e)
1 //===-- DataflowEnvironment.cpp ---------------------------------*- 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 //  This file defines an Environment class that is used by dataflow analyses
10 //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11 //  program at given program points.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Type.h"
19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
20 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
21 #include "clang/Analysis/FlowSensitive/Value.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/DenseSet.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include <cassert>
26 #include <memory>
27 #include <utility>
28 
29 namespace clang {
30 namespace dataflow {
31 
32 /// Returns a map consisting of key-value entries that are present in both maps.
33 template <typename K, typename V>
34 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
35                                         const llvm::DenseMap<K, V> &Map2) {
36   llvm::DenseMap<K, V> Result;
37   for (auto &Entry : Map1) {
38     auto It = Map2.find(Entry.first);
39     if (It != Map2.end() && Entry.second == It->second)
40       Result.insert({Entry.first, Entry.second});
41   }
42   return Result;
43 }
44 
45 /// Returns true if and only if `Val1` is equivalent to `Val2`.
46 static bool equivalentValues(QualType Type, Value *Val1, Value *Val2,
47                              Environment::ValueModel &Model) {
48   if (Val1 == Val2)
49     return true;
50 
51   if (auto *IndVal1 = dyn_cast<IndirectionValue>(Val1)) {
52     auto *IndVal2 = cast<IndirectionValue>(Val2);
53     assert(IndVal1->getKind() == IndVal2->getKind());
54     return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
55   }
56 
57   return Model.compareEquivalent(Type, *Val1, *Val2);
58 }
59 
60 /// Initializes a global storage value.
61 static void initGlobalVar(const VarDecl &D, Environment &Env) {
62   if (!D.hasGlobalStorage() ||
63       Env.getStorageLocation(D, SkipPast::None) != nullptr)
64     return;
65 
66   auto &Loc = Env.createStorageLocation(D);
67   Env.setStorageLocation(D, Loc);
68   if (auto *Val = Env.createValue(D.getType()))
69     Env.setValue(Loc, *Val);
70 }
71 
72 /// Initializes a global storage value.
73 static void initGlobalVar(const Decl &D, Environment &Env) {
74   if (auto *V = dyn_cast<VarDecl>(&D))
75     initGlobalVar(*V, Env);
76 }
77 
78 /// Initializes global storage values that are declared or referenced from
79 /// sub-statements of `S`.
80 // FIXME: Add support for resetting globals after function calls to enable
81 // the implementation of sound analyses.
82 static void initGlobalVars(const Stmt &S, Environment &Env) {
83   for (auto *Child : S.children()) {
84     if (Child != nullptr)
85       initGlobalVars(*Child, Env);
86   }
87 
88   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
89     if (DS->isSingleDecl()) {
90       initGlobalVar(*DS->getSingleDecl(), Env);
91     } else {
92       for (auto *D : DS->getDeclGroup())
93         initGlobalVar(*D, Env);
94     }
95   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
96     initGlobalVar(*E->getDecl(), Env);
97   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
98     initGlobalVar(*E->getMemberDecl(), Env);
99   }
100 }
101 
102 Environment::Environment(DataflowAnalysisContext &DACtx,
103                          const DeclContext &DeclCtx)
104     : Environment(DACtx) {
105   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
106     assert(FuncDecl->getBody() != nullptr);
107     initGlobalVars(*FuncDecl->getBody(), *this);
108     for (const auto *ParamDecl : FuncDecl->parameters()) {
109       assert(ParamDecl != nullptr);
110       auto &ParamLoc = createStorageLocation(*ParamDecl);
111       setStorageLocation(*ParamDecl, ParamLoc);
112       if (Value *ParamVal = createValue(ParamDecl->getType()))
113         setValue(ParamLoc, *ParamVal);
114     }
115   }
116 
117   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
118     if (!MethodDecl->isStatic()) {
119       QualType ThisPointeeType = MethodDecl->getThisObjectType();
120       // FIXME: Add support for union types.
121       if (!ThisPointeeType->isUnionType()) {
122         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
123         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
124         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
125           setValue(ThisPointeeLoc, *ThisPointeeVal);
126       }
127     }
128   }
129 }
130 
131 bool Environment::equivalentTo(const Environment &Other,
132                                Environment::ValueModel &Model) const {
133   assert(DACtx == Other.DACtx);
134 
135   if (DeclToLoc != Other.DeclToLoc)
136     return false;
137 
138   if (ExprToLoc != Other.ExprToLoc)
139     return false;
140 
141   if (LocToVal.size() != Other.LocToVal.size())
142     return false;
143 
144   for (auto &Entry : LocToVal) {
145     const StorageLocation *Loc = Entry.first;
146     assert(Loc != nullptr);
147 
148     Value *Val = Entry.second;
149     assert(Val != nullptr);
150 
151     auto It = Other.LocToVal.find(Loc);
152     if (It == Other.LocToVal.end())
153       return false;
154     assert(It->second != nullptr);
155 
156     if (!equivalentValues(Loc->getType(), Val, It->second, Model))
157       return false;
158   }
159 
160   return true;
161 }
162 
163 LatticeJoinEffect Environment::join(const Environment &Other,
164                                     Environment::ValueModel &Model) {
165   assert(DACtx == Other.DACtx);
166 
167   auto Effect = LatticeJoinEffect::Unchanged;
168 
169   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
170   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
171   if (DeclToLocSizeBefore != DeclToLoc.size())
172     Effect = LatticeJoinEffect::Changed;
173 
174   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
175   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
176   if (ExprToLocSizeBefore != ExprToLoc.size())
177     Effect = LatticeJoinEffect::Changed;
178 
179   // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
180   // values to storage locations while this code iterates over the current
181   // assignments.
182   llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
183       std::move(LocToVal);
184   for (auto &Entry : OldLocToVal) {
185     const StorageLocation *Loc = Entry.first;
186     assert(Loc != nullptr);
187 
188     Value *Val = Entry.second;
189     assert(Val != nullptr);
190 
191     auto It = Other.LocToVal.find(Loc);
192     if (It == Other.LocToVal.end())
193       continue;
194     assert(It->second != nullptr);
195 
196     if (equivalentValues(Loc->getType(), Val, It->second, Model)) {
197       LocToVal.insert({Loc, Val});
198       continue;
199     }
200 
201     // FIXME: Consider destroying `MergedValue` immediately if
202     // `ValueModel::merge` returns false to avoid storing unneeded values in
203     // `DACtx`.
204     if (Value *MergedVal = createValue(Loc->getType()))
205       if (Model.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
206         LocToVal.insert({Loc, MergedVal});
207   }
208   if (OldLocToVal.size() != LocToVal.size())
209     Effect = LatticeJoinEffect::Changed;
210 
211   return Effect;
212 }
213 
214 StorageLocation &Environment::createStorageLocation(QualType Type) {
215   assert(!Type.isNull());
216   if (Type->isStructureOrClassType() || Type->isUnionType()) {
217     // FIXME: Explore options to avoid eager initialization of fields as some of
218     // them might not be needed for a particular analysis.
219     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
220     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
221       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
222     }
223     return takeOwnership(
224         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
225   }
226   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
227 }
228 
229 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
230   // Evaluated declarations are always assigned the same storage locations to
231   // ensure that the environment stabilizes across loop iterations. Storage
232   // locations for evaluated declarations are stored in the analysis context.
233   if (auto *Loc = DACtx->getStorageLocation(D))
234     return *Loc;
235   auto &Loc = createStorageLocation(D.getType());
236   DACtx->setStorageLocation(D, Loc);
237   return Loc;
238 }
239 
240 StorageLocation &Environment::createStorageLocation(const Expr &E) {
241   // Evaluated expressions are always assigned the same storage locations to
242   // ensure that the environment stabilizes across loop iterations. Storage
243   // locations for evaluated expressions are stored in the analysis context.
244   if (auto *Loc = DACtx->getStorageLocation(E))
245     return *Loc;
246   auto &Loc = createStorageLocation(E.getType());
247   DACtx->setStorageLocation(E, Loc);
248   return Loc;
249 }
250 
251 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
252   assert(DeclToLoc.find(&D) == DeclToLoc.end());
253   DeclToLoc[&D] = &Loc;
254 }
255 
256 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
257                                                  SkipPast SP) const {
258   auto It = DeclToLoc.find(&D);
259   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
260 }
261 
262 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
263   assert(ExprToLoc.find(&E) == ExprToLoc.end());
264   ExprToLoc[&E] = &Loc;
265 }
266 
267 StorageLocation *Environment::getStorageLocation(const Expr &E,
268                                                  SkipPast SP) const {
269   auto It = ExprToLoc.find(&E);
270   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
271 }
272 
273 StorageLocation *Environment::getThisPointeeStorageLocation() const {
274   return DACtx->getThisPointeeStorageLocation();
275 }
276 
277 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
278   LocToVal[&Loc] = &Val;
279 
280   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
281     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
282 
283     const QualType Type = AggregateLoc.getType();
284     assert(Type->isStructureOrClassType());
285 
286     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
287       assert(Field != nullptr);
288       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
289     }
290   }
291 }
292 
293 Value *Environment::getValue(const StorageLocation &Loc) const {
294   auto It = LocToVal.find(&Loc);
295   return It == LocToVal.end() ? nullptr : It->second;
296 }
297 
298 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
299   auto *Loc = getStorageLocation(D, SP);
300   if (Loc == nullptr)
301     return nullptr;
302   return getValue(*Loc);
303 }
304 
305 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
306   auto *Loc = getStorageLocation(E, SP);
307   if (Loc == nullptr)
308     return nullptr;
309   return getValue(*Loc);
310 }
311 
312 Value *Environment::createValue(QualType Type) {
313   llvm::DenseSet<QualType> Visited;
314   return createValueUnlessSelfReferential(Type, Visited);
315 }
316 
317 Value *Environment::createValueUnlessSelfReferential(
318     QualType Type, llvm::DenseSet<QualType> &Visited) {
319   assert(!Type.isNull());
320 
321   if (Type->isIntegerType()) {
322     return &takeOwnership(std::make_unique<IntegerValue>());
323   }
324 
325   if (Type->isReferenceType()) {
326     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
327     auto &PointeeLoc = createStorageLocation(PointeeType);
328 
329     if (!Visited.contains(PointeeType.getCanonicalType())) {
330       Visited.insert(PointeeType.getCanonicalType());
331       Value *PointeeVal =
332           createValueUnlessSelfReferential(PointeeType, Visited);
333       Visited.erase(PointeeType.getCanonicalType());
334 
335       if (PointeeVal != nullptr)
336         setValue(PointeeLoc, *PointeeVal);
337     }
338 
339     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
340   }
341 
342   if (Type->isPointerType()) {
343     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
344     auto &PointeeLoc = createStorageLocation(PointeeType);
345 
346     if (!Visited.contains(PointeeType.getCanonicalType())) {
347       Visited.insert(PointeeType.getCanonicalType());
348       Value *PointeeVal =
349           createValueUnlessSelfReferential(PointeeType, Visited);
350       Visited.erase(PointeeType.getCanonicalType());
351 
352       if (PointeeVal != nullptr)
353         setValue(PointeeLoc, *PointeeVal);
354     }
355 
356     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
357   }
358 
359   if (Type->isStructureOrClassType()) {
360     // FIXME: Initialize only fields that are accessed in the context that is
361     // being analyzed.
362     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
363     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
364       assert(Field != nullptr);
365 
366       QualType FieldType = Field->getType();
367       if (Visited.contains(FieldType.getCanonicalType()))
368         continue;
369 
370       Visited.insert(FieldType.getCanonicalType());
371       FieldValues.insert(
372           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
373       Visited.erase(FieldType.getCanonicalType());
374     }
375 
376     return &takeOwnership(
377         std::make_unique<StructValue>(std::move(FieldValues)));
378   }
379 
380   return nullptr;
381 }
382 
383 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
384   switch (SP) {
385   case SkipPast::None:
386     return Loc;
387   case SkipPast::Reference:
388     // References cannot be chained so we only need to skip past one level of
389     // indirection.
390     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
391       return Val->getPointeeLoc();
392     return Loc;
393   case SkipPast::ReferenceThenPointer:
394     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
395     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
396       return Val->getPointeeLoc();
397     return LocPastRef;
398   }
399   llvm_unreachable("bad SkipPast kind");
400 }
401 
402 const StorageLocation &Environment::skip(const StorageLocation &Loc,
403                                          SkipPast SP) const {
404   return skip(*const_cast<StorageLocation *>(&Loc), SP);
405 }
406 
407 } // namespace dataflow
408 } // namespace clang
409