xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision 7ea103de140b59a64fc884fa90afd2213619384d)
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       const auto &D = *cast<VarDecl>(DS->getSingleDecl());
91       initGlobalVar(D, Env);
92     } else {
93       for (auto *D : DS->getDeclGroup())
94         initGlobalVar(*D, Env);
95     }
96   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
97     initGlobalVar(*E->getDecl(), Env);
98   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
99     initGlobalVar(*E->getMemberDecl(), Env);
100   }
101 }
102 
103 Environment::Environment(DataflowAnalysisContext &DACtx,
104                          const DeclContext &DeclCtx)
105     : Environment(DACtx) {
106   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
107     assert(FuncDecl->getBody() != nullptr);
108     initGlobalVars(*FuncDecl->getBody(), *this);
109     for (const auto *ParamDecl : FuncDecl->parameters()) {
110       assert(ParamDecl != nullptr);
111       auto &ParamLoc = createStorageLocation(*ParamDecl);
112       setStorageLocation(*ParamDecl, ParamLoc);
113       if (Value *ParamVal = createValue(ParamDecl->getType()))
114         setValue(ParamLoc, *ParamVal);
115     }
116   }
117 
118   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
119     if (!MethodDecl->isStatic()) {
120       QualType ThisPointeeType = MethodDecl->getThisObjectType();
121       // FIXME: Add support for union types.
122       if (!ThisPointeeType->isUnionType()) {
123         auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
124         DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
125         if (Value *ThisPointeeVal = createValue(ThisPointeeType))
126           setValue(ThisPointeeLoc, *ThisPointeeVal);
127       }
128     }
129   }
130 }
131 
132 bool Environment::equivalentTo(const Environment &Other,
133                                Environment::ValueModel &Model) const {
134   assert(DACtx == Other.DACtx);
135 
136   if (DeclToLoc != Other.DeclToLoc)
137     return false;
138 
139   if (ExprToLoc != Other.ExprToLoc)
140     return false;
141 
142   if (LocToVal.size() != Other.LocToVal.size())
143     return false;
144 
145   for (auto &Entry : LocToVal) {
146     const StorageLocation *Loc = Entry.first;
147     assert(Loc != nullptr);
148 
149     Value *Val = Entry.second;
150     assert(Val != nullptr);
151 
152     auto It = Other.LocToVal.find(Loc);
153     if (It == Other.LocToVal.end())
154       return false;
155     assert(It->second != nullptr);
156 
157     if (!equivalentValues(Loc->getType(), Val, It->second, Model))
158       return false;
159   }
160 
161   return true;
162 }
163 
164 LatticeJoinEffect Environment::join(const Environment &Other,
165                                     Environment::ValueModel &Model) {
166   assert(DACtx == Other.DACtx);
167 
168   auto Effect = LatticeJoinEffect::Unchanged;
169 
170   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
171   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
172   if (DeclToLocSizeBefore != DeclToLoc.size())
173     Effect = LatticeJoinEffect::Changed;
174 
175   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
176   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
177   if (ExprToLocSizeBefore != ExprToLoc.size())
178     Effect = LatticeJoinEffect::Changed;
179 
180   // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
181   // values to storage locations while this code iterates over the current
182   // assignments.
183   llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
184       std::move(LocToVal);
185   for (auto &Entry : OldLocToVal) {
186     const StorageLocation *Loc = Entry.first;
187     assert(Loc != nullptr);
188 
189     Value *Val = Entry.second;
190     assert(Val != nullptr);
191 
192     auto It = Other.LocToVal.find(Loc);
193     if (It == Other.LocToVal.end())
194       continue;
195     assert(It->second != nullptr);
196 
197     if (equivalentValues(Loc->getType(), Val, It->second, Model)) {
198       LocToVal.insert({Loc, Val});
199       continue;
200     }
201 
202     // FIXME: Consider destroying `MergedValue` immediately if
203     // `ValueModel::merge` returns false to avoid storing unneeded values in
204     // `DACtx`.
205     if (Value *MergedVal = createValue(Loc->getType()))
206       if (Model.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
207         LocToVal.insert({Loc, MergedVal});
208   }
209   if (OldLocToVal.size() != LocToVal.size())
210     Effect = LatticeJoinEffect::Changed;
211 
212   return Effect;
213 }
214 
215 StorageLocation &Environment::createStorageLocation(QualType Type) {
216   assert(!Type.isNull());
217   if (Type->isStructureOrClassType() || Type->isUnionType()) {
218     // FIXME: Explore options to avoid eager initialization of fields as some of
219     // them might not be needed for a particular analysis.
220     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
221     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
222       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
223     }
224     return takeOwnership(
225         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
226   }
227   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
228 }
229 
230 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
231   // Evaluated declarations are always assigned the same storage locations to
232   // ensure that the environment stabilizes across loop iterations. Storage
233   // locations for evaluated declarations are stored in the analysis context.
234   if (auto *Loc = DACtx->getStorageLocation(D))
235     return *Loc;
236   auto &Loc = createStorageLocation(D.getType());
237   DACtx->setStorageLocation(D, Loc);
238   return Loc;
239 }
240 
241 StorageLocation &Environment::createStorageLocation(const Expr &E) {
242   // Evaluated expressions are always assigned the same storage locations to
243   // ensure that the environment stabilizes across loop iterations. Storage
244   // locations for evaluated expressions are stored in the analysis context.
245   if (auto *Loc = DACtx->getStorageLocation(E))
246     return *Loc;
247   auto &Loc = createStorageLocation(E.getType());
248   DACtx->setStorageLocation(E, Loc);
249   return Loc;
250 }
251 
252 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
253   assert(DeclToLoc.find(&D) == DeclToLoc.end());
254   DeclToLoc[&D] = &Loc;
255 }
256 
257 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
258                                                  SkipPast SP) const {
259   auto It = DeclToLoc.find(&D);
260   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
261 }
262 
263 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
264   assert(ExprToLoc.find(&E) == ExprToLoc.end());
265   ExprToLoc[&E] = &Loc;
266 }
267 
268 StorageLocation *Environment::getStorageLocation(const Expr &E,
269                                                  SkipPast SP) const {
270   auto It = ExprToLoc.find(&E);
271   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
272 }
273 
274 StorageLocation *Environment::getThisPointeeStorageLocation() const {
275   return DACtx->getThisPointeeStorageLocation();
276 }
277 
278 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
279   LocToVal[&Loc] = &Val;
280 
281   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
282     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
283 
284     const QualType Type = AggregateLoc.getType();
285     assert(Type->isStructureOrClassType());
286 
287     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
288       assert(Field != nullptr);
289       setValue(AggregateLoc.getChild(*Field), StructVal->getChild(*Field));
290     }
291   }
292 }
293 
294 Value *Environment::getValue(const StorageLocation &Loc) const {
295   auto It = LocToVal.find(&Loc);
296   return It == LocToVal.end() ? nullptr : It->second;
297 }
298 
299 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
300   auto *Loc = getStorageLocation(D, SP);
301   if (Loc == nullptr)
302     return nullptr;
303   return getValue(*Loc);
304 }
305 
306 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
307   auto *Loc = getStorageLocation(E, SP);
308   if (Loc == nullptr)
309     return nullptr;
310   return getValue(*Loc);
311 }
312 
313 Value *Environment::createValue(QualType Type) {
314   llvm::DenseSet<QualType> Visited;
315   return createValueUnlessSelfReferential(Type, Visited);
316 }
317 
318 Value *Environment::createValueUnlessSelfReferential(
319     QualType Type, llvm::DenseSet<QualType> &Visited) {
320   assert(!Type.isNull());
321 
322   if (Type->isIntegerType()) {
323     return &takeOwnership(std::make_unique<IntegerValue>());
324   }
325 
326   if (Type->isReferenceType()) {
327     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
328     auto &PointeeLoc = createStorageLocation(PointeeType);
329 
330     if (!Visited.contains(PointeeType.getCanonicalType())) {
331       Visited.insert(PointeeType.getCanonicalType());
332       Value *PointeeVal =
333           createValueUnlessSelfReferential(PointeeType, Visited);
334       Visited.erase(PointeeType.getCanonicalType());
335 
336       if (PointeeVal != nullptr)
337         setValue(PointeeLoc, *PointeeVal);
338     }
339 
340     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
341   }
342 
343   if (Type->isPointerType()) {
344     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
345     auto &PointeeLoc = createStorageLocation(PointeeType);
346 
347     if (!Visited.contains(PointeeType.getCanonicalType())) {
348       Visited.insert(PointeeType.getCanonicalType());
349       Value *PointeeVal =
350           createValueUnlessSelfReferential(PointeeType, Visited);
351       Visited.erase(PointeeType.getCanonicalType());
352 
353       if (PointeeVal != nullptr)
354         setValue(PointeeLoc, *PointeeVal);
355     }
356 
357     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
358   }
359 
360   if (Type->isStructureOrClassType()) {
361     // FIXME: Initialize only fields that are accessed in the context that is
362     // being analyzed.
363     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
364     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
365       assert(Field != nullptr);
366 
367       QualType FieldType = Field->getType();
368       if (Visited.contains(FieldType.getCanonicalType()))
369         continue;
370 
371       Visited.insert(FieldType.getCanonicalType());
372       FieldValues.insert(
373           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
374       Visited.erase(FieldType.getCanonicalType());
375     }
376 
377     return &takeOwnership(
378         std::make_unique<StructValue>(std::move(FieldValues)));
379   }
380 
381   return nullptr;
382 }
383 
384 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
385   switch (SP) {
386   case SkipPast::None:
387     return Loc;
388   case SkipPast::Reference:
389     // References cannot be chained so we only need to skip past one level of
390     // indirection.
391     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
392       return Val->getPointeeLoc();
393     return Loc;
394   case SkipPast::ReferenceThenPointer:
395     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
396     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
397       return Val->getPointeeLoc();
398     return LocPastRef;
399   }
400   llvm_unreachable("bad SkipPast kind");
401 }
402 
403 const StorageLocation &Environment::skip(const StorageLocation &Loc,
404                                          SkipPast SP) const {
405   return skip(*const_cast<StorageLocation *>(&Loc), SP);
406 }
407 
408 } // namespace dataflow
409 } // namespace clang
410