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