xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision baa0f221d6df2fcce10c54751cc42284e2656c31)
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 (MemberLocToStruct != Other.MemberLocToStruct)
142     return false;
143 
144   if (LocToVal.size() != Other.LocToVal.size())
145     return false;
146 
147   for (auto &Entry : LocToVal) {
148     const StorageLocation *Loc = Entry.first;
149     assert(Loc != nullptr);
150 
151     Value *Val = Entry.second;
152     assert(Val != nullptr);
153 
154     auto It = Other.LocToVal.find(Loc);
155     if (It == Other.LocToVal.end())
156       return false;
157     assert(It->second != nullptr);
158 
159     if (!equivalentValues(Loc->getType(), Val, It->second, Model))
160       return false;
161   }
162 
163   return true;
164 }
165 
166 LatticeJoinEffect Environment::join(const Environment &Other,
167                                     Environment::ValueModel &Model) {
168   assert(DACtx == Other.DACtx);
169 
170   auto Effect = LatticeJoinEffect::Unchanged;
171 
172   const unsigned DeclToLocSizeBefore = DeclToLoc.size();
173   DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
174   if (DeclToLocSizeBefore != DeclToLoc.size())
175     Effect = LatticeJoinEffect::Changed;
176 
177   const unsigned ExprToLocSizeBefore = ExprToLoc.size();
178   ExprToLoc = intersectDenseMaps(ExprToLoc, Other.ExprToLoc);
179   if (ExprToLocSizeBefore != ExprToLoc.size())
180     Effect = LatticeJoinEffect::Changed;
181 
182   const unsigned MemberLocToStructSizeBefore = MemberLocToStruct.size();
183   MemberLocToStruct =
184       intersectDenseMaps(MemberLocToStruct, Other.MemberLocToStruct);
185   if (MemberLocToStructSizeBefore != MemberLocToStruct.size())
186     Effect = LatticeJoinEffect::Changed;
187 
188   // Move `LocToVal` so that `Environment::ValueModel::merge` can safely assign
189   // values to storage locations while this code iterates over the current
190   // assignments.
191   llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
192       std::move(LocToVal);
193   for (auto &Entry : OldLocToVal) {
194     const StorageLocation *Loc = Entry.first;
195     assert(Loc != nullptr);
196 
197     Value *Val = Entry.second;
198     assert(Val != nullptr);
199 
200     auto It = Other.LocToVal.find(Loc);
201     if (It == Other.LocToVal.end())
202       continue;
203     assert(It->second != nullptr);
204 
205     if (equivalentValues(Loc->getType(), Val, It->second, Model)) {
206       LocToVal.insert({Loc, Val});
207       continue;
208     }
209 
210     // FIXME: Consider destroying `MergedValue` immediately if
211     // `ValueModel::merge` returns false to avoid storing unneeded values in
212     // `DACtx`.
213     if (Value *MergedVal = createValue(Loc->getType()))
214       if (Model.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
215         LocToVal.insert({Loc, MergedVal});
216   }
217   if (OldLocToVal.size() != LocToVal.size())
218     Effect = LatticeJoinEffect::Changed;
219 
220   return Effect;
221 }
222 
223 StorageLocation &Environment::createStorageLocation(QualType Type) {
224   assert(!Type.isNull());
225   if (Type->isStructureOrClassType() || Type->isUnionType()) {
226     // FIXME: Explore options to avoid eager initialization of fields as some of
227     // them might not be needed for a particular analysis.
228     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
229     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
230       FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
231     }
232     return takeOwnership(
233         std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
234   }
235   return takeOwnership(std::make_unique<ScalarStorageLocation>(Type));
236 }
237 
238 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
239   // Evaluated declarations are always assigned the same storage locations to
240   // ensure that the environment stabilizes across loop iterations. Storage
241   // locations for evaluated declarations are stored in the analysis context.
242   if (auto *Loc = DACtx->getStorageLocation(D))
243     return *Loc;
244   auto &Loc = createStorageLocation(D.getType());
245   DACtx->setStorageLocation(D, Loc);
246   return Loc;
247 }
248 
249 StorageLocation &Environment::createStorageLocation(const Expr &E) {
250   // Evaluated expressions are always assigned the same storage locations to
251   // ensure that the environment stabilizes across loop iterations. Storage
252   // locations for evaluated expressions are stored in the analysis context.
253   if (auto *Loc = DACtx->getStorageLocation(E))
254     return *Loc;
255   auto &Loc = createStorageLocation(E.getType());
256   DACtx->setStorageLocation(E, Loc);
257   return Loc;
258 }
259 
260 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
261   assert(DeclToLoc.find(&D) == DeclToLoc.end());
262   DeclToLoc[&D] = &Loc;
263 }
264 
265 StorageLocation *Environment::getStorageLocation(const ValueDecl &D,
266                                                  SkipPast SP) const {
267   auto It = DeclToLoc.find(&D);
268   return It == DeclToLoc.end() ? nullptr : &skip(*It->second, SP);
269 }
270 
271 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
272   assert(ExprToLoc.find(&E) == ExprToLoc.end());
273   ExprToLoc[&E] = &Loc;
274 }
275 
276 StorageLocation *Environment::getStorageLocation(const Expr &E,
277                                                  SkipPast SP) const {
278   auto It = ExprToLoc.find(&E);
279   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
280 }
281 
282 StorageLocation *Environment::getThisPointeeStorageLocation() const {
283   return DACtx->getThisPointeeStorageLocation();
284 }
285 
286 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
287   LocToVal[&Loc] = &Val;
288 
289   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
290     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
291 
292     const QualType Type = AggregateLoc.getType();
293     assert(Type->isStructureOrClassType());
294 
295     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
296       assert(Field != nullptr);
297       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
298       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
299       setValue(FieldLoc, StructVal->getChild(*Field));
300     }
301   }
302 
303   auto IT = MemberLocToStruct.find(&Loc);
304   if (IT != MemberLocToStruct.end()) {
305     // `Loc` is the location of a struct member so we need to also update the
306     // value of the member in the corresponding `StructValue`.
307 
308     assert(IT->second.first != nullptr);
309     StructValue &StructVal = *IT->second.first;
310 
311     assert(IT->second.second != nullptr);
312     const ValueDecl &Member = *IT->second.second;
313 
314     StructVal.setChild(Member, Val);
315   }
316 }
317 
318 Value *Environment::getValue(const StorageLocation &Loc) const {
319   auto It = LocToVal.find(&Loc);
320   return It == LocToVal.end() ? nullptr : It->second;
321 }
322 
323 Value *Environment::getValue(const ValueDecl &D, SkipPast SP) const {
324   auto *Loc = getStorageLocation(D, SP);
325   if (Loc == nullptr)
326     return nullptr;
327   return getValue(*Loc);
328 }
329 
330 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
331   auto *Loc = getStorageLocation(E, SP);
332   if (Loc == nullptr)
333     return nullptr;
334   return getValue(*Loc);
335 }
336 
337 Value *Environment::createValue(QualType Type) {
338   llvm::DenseSet<QualType> Visited;
339   return createValueUnlessSelfReferential(Type, Visited);
340 }
341 
342 Value *Environment::createValueUnlessSelfReferential(
343     QualType Type, llvm::DenseSet<QualType> &Visited) {
344   assert(!Type.isNull());
345 
346   if (Type->isIntegerType()) {
347     return &takeOwnership(std::make_unique<IntegerValue>());
348   }
349 
350   if (Type->isReferenceType()) {
351     QualType PointeeType = Type->getAs<ReferenceType>()->getPointeeType();
352     auto &PointeeLoc = createStorageLocation(PointeeType);
353 
354     if (!Visited.contains(PointeeType.getCanonicalType())) {
355       Visited.insert(PointeeType.getCanonicalType());
356       Value *PointeeVal =
357           createValueUnlessSelfReferential(PointeeType, Visited);
358       Visited.erase(PointeeType.getCanonicalType());
359 
360       if (PointeeVal != nullptr)
361         setValue(PointeeLoc, *PointeeVal);
362     }
363 
364     return &takeOwnership(std::make_unique<ReferenceValue>(PointeeLoc));
365   }
366 
367   if (Type->isPointerType()) {
368     QualType PointeeType = Type->getAs<PointerType>()->getPointeeType();
369     auto &PointeeLoc = createStorageLocation(PointeeType);
370 
371     if (!Visited.contains(PointeeType.getCanonicalType())) {
372       Visited.insert(PointeeType.getCanonicalType());
373       Value *PointeeVal =
374           createValueUnlessSelfReferential(PointeeType, Visited);
375       Visited.erase(PointeeType.getCanonicalType());
376 
377       if (PointeeVal != nullptr)
378         setValue(PointeeLoc, *PointeeVal);
379     }
380 
381     return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
382   }
383 
384   if (Type->isStructureOrClassType()) {
385     // FIXME: Initialize only fields that are accessed in the context that is
386     // being analyzed.
387     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
388     for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) {
389       assert(Field != nullptr);
390 
391       QualType FieldType = Field->getType();
392       if (Visited.contains(FieldType.getCanonicalType()))
393         continue;
394 
395       Visited.insert(FieldType.getCanonicalType());
396       FieldValues.insert(
397           {Field, createValueUnlessSelfReferential(FieldType, Visited)});
398       Visited.erase(FieldType.getCanonicalType());
399     }
400 
401     return &takeOwnership(
402         std::make_unique<StructValue>(std::move(FieldValues)));
403   }
404 
405   return nullptr;
406 }
407 
408 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
409   switch (SP) {
410   case SkipPast::None:
411     return Loc;
412   case SkipPast::Reference:
413     // References cannot be chained so we only need to skip past one level of
414     // indirection.
415     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
416       return Val->getPointeeLoc();
417     return Loc;
418   case SkipPast::ReferenceThenPointer:
419     StorageLocation &LocPastRef = skip(Loc, SkipPast::Reference);
420     if (auto *Val = dyn_cast_or_null<PointerValue>(getValue(LocPastRef)))
421       return Val->getPointeeLoc();
422     return LocPastRef;
423   }
424   llvm_unreachable("bad SkipPast kind");
425 }
426 
427 const StorageLocation &Environment::skip(const StorageLocation &Loc,
428                                          SkipPast SP) const {
429   return skip(*const_cast<StorageLocation *>(&Loc), SP);
430 }
431 
432 } // namespace dataflow
433 } // namespace clang
434