1 //===-- Transfer.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 transfer functions that evaluate program statements and
10 //  update an environment accordingly.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Analysis/FlowSensitive/Transfer.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclBase.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/ExprCXX.h"
20 #include "clang/AST/OperationKinds.h"
21 #include "clang/AST/Stmt.h"
22 #include "clang/AST/StmtVisitor.h"
23 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
24 #include "clang/Analysis/FlowSensitive/Value.h"
25 #include "clang/Basic/OperatorKinds.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/Support/Casting.h"
28 #include <cassert>
29 #include <memory>
30 #include <tuple>
31 
32 namespace clang {
33 namespace dataflow {
34 
35 static const Expr *skipExprWithCleanups(const Expr *E) {
36   if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E))
37     return C->getSubExpr();
38   return E;
39 }
40 
41 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
42                                           Environment &Env) {
43   // Equality of booleans involves implicit integral casts. Ignore these casts
44   // for now and focus on the values associated with the wrapped expressions.
45   // FIXME: Consider changing this once the framework offers better support for
46   // integral casts.
47   const Expr *LHSNorm = LHS.IgnoreCasts();
48   const Expr *RHSNorm = RHS.IgnoreCasts();
49   assert(LHSNorm != nullptr);
50   assert(RHSNorm != nullptr);
51 
52   if (auto *LHSValue = dyn_cast_or_null<BoolValue>(
53           Env.getValue(*LHSNorm, SkipPast::Reference)))
54     if (auto *RHSValue = dyn_cast_or_null<BoolValue>(
55             Env.getValue(*RHSNorm, SkipPast::Reference)))
56       return Env.makeIff(*LHSValue, *RHSValue);
57 
58   return Env.makeAtomicBoolValue();
59 }
60 
61 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
62 public:
63   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
64       : StmtToEnv(StmtToEnv), Env(Env) {}
65 
66   void VisitBinaryOperator(const BinaryOperator *S) {
67     // The CFG does not contain `ParenExpr` as top-level statements in basic
68     // blocks, however sub-expressions can still be of that type.
69     assert(S->getLHS() != nullptr);
70     const Expr *LHS = S->getLHS()->IgnoreParens();
71     assert(LHS != nullptr);
72 
73     assert(S->getRHS() != nullptr);
74     const Expr *RHS = S->getRHS()->IgnoreParens();
75     assert(RHS != nullptr);
76 
77     switch (S->getOpcode()) {
78     case BO_Assign: {
79       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
80       if (LHSLoc == nullptr)
81         break;
82 
83       auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
84       if (RHSVal == nullptr)
85         break;
86 
87       // Assign a value to the storage location of the left-hand side.
88       Env.setValue(*LHSLoc, *RHSVal);
89 
90       // Assign a storage location for the whole expression.
91       Env.setStorageLocation(*S, *LHSLoc);
92       break;
93     }
94     case BO_LAnd:
95     case BO_LOr: {
96       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
97       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
98 
99       auto &Loc = Env.createStorageLocation(*S);
100       Env.setStorageLocation(*S, Loc);
101       if (S->getOpcode() == BO_LAnd)
102         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
103       else
104         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
105       break;
106     }
107     case BO_NE:
108     case BO_EQ: {
109       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
110       auto &Loc = Env.createStorageLocation(*S);
111       Env.setStorageLocation(*S, Loc);
112       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
113                                                 : Env.makeNot(LHSEqRHSValue));
114       break;
115     }
116     default:
117       break;
118     }
119   }
120 
121   void VisitDeclRefExpr(const DeclRefExpr *S) {
122     assert(S->getDecl() != nullptr);
123     auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
124     if (DeclLoc == nullptr)
125       return;
126 
127     if (S->getDecl()->getType()->isReferenceType()) {
128       Env.setStorageLocation(*S, *DeclLoc);
129     } else {
130       auto &Loc = Env.createStorageLocation(*S);
131       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
132       Env.setStorageLocation(*S, Loc);
133       Env.setValue(Loc, Val);
134     }
135   }
136 
137   void VisitDeclStmt(const DeclStmt *S) {
138     // Group decls are converted into single decls in the CFG so the cast below
139     // is safe.
140     const auto &D = *cast<VarDecl>(S->getSingleDecl());
141 
142     // Static local vars are already initialized in `Environment`.
143     if (D.hasGlobalStorage())
144       return;
145 
146     auto &Loc = Env.createStorageLocation(D);
147     Env.setStorageLocation(D, Loc);
148 
149     const Expr *InitExpr = D.getInit();
150     if (InitExpr == nullptr) {
151       // No initializer expression - associate `Loc` with a new value.
152       if (Value *Val = Env.createValue(D.getType()))
153         Env.setValue(Loc, *Val);
154       return;
155     }
156 
157     // The CFG does not contain `ParenExpr` as top-level statements in basic
158     // blocks, however sub-expressions can still be of that type.
159     InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens());
160     assert(InitExpr != nullptr);
161 
162     if (D.getType()->isReferenceType()) {
163       // Initializing a reference variable - do not create a reference to
164       // reference.
165       if (auto *InitExprLoc =
166               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
167         auto &Val =
168             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
169         Env.setValue(Loc, Val);
170       } else {
171         // FIXME: The initializer expression must always be assigned a value.
172         // Replace this with an assert when we have sufficient coverage of
173         // language features.
174         if (Value *Val = Env.createValue(D.getType()))
175           Env.setValue(Loc, *Val);
176       }
177       return;
178     }
179 
180     if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
181       Env.setValue(Loc, *InitExprVal);
182     } else if (!D.getType()->isStructureOrClassType()) {
183       // FIXME: The initializer expression must always be assigned a value.
184       // Replace this with an assert when we have sufficient coverage of
185       // language features.
186       if (Value *Val = Env.createValue(D.getType()))
187         Env.setValue(Loc, *Val);
188     } else {
189       llvm_unreachable("structs and classes must always be assigned values");
190     }
191   }
192 
193   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
194     // The CFG does not contain `ParenExpr` as top-level statements in basic
195     // blocks, however sub-expressions can still be of that type.
196     assert(S->getSubExpr() != nullptr);
197     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
198     assert(SubExpr != nullptr);
199 
200     switch (S->getCastKind()) {
201     case CK_LValueToRValue: {
202       auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
203       if (SubExprVal == nullptr)
204         break;
205 
206       auto &ExprLoc = Env.createStorageLocation(*S);
207       Env.setStorageLocation(*S, ExprLoc);
208       Env.setValue(ExprLoc, *SubExprVal);
209       break;
210     }
211     case CK_UncheckedDerivedToBase:
212     case CK_ConstructorConversion:
213     case CK_UserDefinedConversion:
214       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
215       // CK_ConstructorConversion, and CK_UserDefinedConversion.
216     case CK_NoOp: {
217       // FIXME: Consider making `Environment::getStorageLocation` skip noop
218       // expressions (this and other similar expressions in the file) instead of
219       // assigning them storage locations.
220       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
221       if (SubExprLoc == nullptr)
222         break;
223 
224       Env.setStorageLocation(*S, *SubExprLoc);
225       break;
226     }
227     default:
228       break;
229     }
230   }
231 
232   void VisitUnaryOperator(const UnaryOperator *S) {
233     // The CFG does not contain `ParenExpr` as top-level statements in basic
234     // blocks, however sub-expressions can still be of that type.
235     assert(S->getSubExpr() != nullptr);
236     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
237     assert(SubExpr != nullptr);
238 
239     switch (S->getOpcode()) {
240     case UO_Deref: {
241       // Skip past a reference to handle dereference of a dependent pointer.
242       const auto *SubExprVal = cast_or_null<PointerValue>(
243           Env.getValue(*SubExpr, SkipPast::Reference));
244       if (SubExprVal == nullptr)
245         break;
246 
247       auto &Loc = Env.createStorageLocation(*S);
248       Env.setStorageLocation(*S, Loc);
249       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
250                             SubExprVal->getPointeeLoc())));
251       break;
252     }
253     case UO_AddrOf: {
254       // Do not form a pointer to a reference. If `SubExpr` is assigned a
255       // `ReferenceValue` then form a value that points to the location of its
256       // pointee.
257       StorageLocation *PointeeLoc =
258           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
259       if (PointeeLoc == nullptr)
260         break;
261 
262       auto &PointerLoc = Env.createStorageLocation(*S);
263       auto &PointerVal =
264           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
265       Env.setStorageLocation(*S, PointerLoc);
266       Env.setValue(PointerLoc, PointerVal);
267       break;
268     }
269     case UO_LNot: {
270       auto *SubExprVal =
271           dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
272       if (SubExprVal == nullptr)
273         break;
274 
275       auto &ExprLoc = Env.createStorageLocation(*S);
276       Env.setStorageLocation(*S, ExprLoc);
277       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
278       break;
279     }
280     default:
281       break;
282     }
283   }
284 
285   void VisitCXXThisExpr(const CXXThisExpr *S) {
286     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
287     assert(ThisPointeeLoc != nullptr);
288 
289     auto &Loc = Env.createStorageLocation(*S);
290     Env.setStorageLocation(*S, Loc);
291     Env.setValue(Loc, Env.takeOwnership(
292                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
293   }
294 
295   void VisitMemberExpr(const MemberExpr *S) {
296     ValueDecl *Member = S->getMemberDecl();
297     assert(Member != nullptr);
298 
299     // FIXME: Consider assigning pointer values to function member expressions.
300     if (Member->isFunctionOrFunctionTemplate())
301       return;
302 
303     if (auto *D = dyn_cast<VarDecl>(Member)) {
304       if (D->hasGlobalStorage()) {
305         auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
306         if (VarDeclLoc == nullptr)
307           return;
308 
309         if (VarDeclLoc->getType()->isReferenceType()) {
310           Env.setStorageLocation(*S, *VarDeclLoc);
311         } else {
312           auto &Loc = Env.createStorageLocation(*S);
313           Env.setStorageLocation(*S, Loc);
314           Env.setValue(Loc, Env.takeOwnership(
315                                 std::make_unique<ReferenceValue>(*VarDeclLoc)));
316         }
317         return;
318       }
319     }
320 
321     // The receiver can be either a value or a pointer to a value. Skip past the
322     // indirection to handle both cases.
323     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
324         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
325     if (BaseLoc == nullptr)
326       return;
327 
328     // FIXME: Add support for union types.
329     if (BaseLoc->getType()->isUnionType())
330       return;
331 
332     auto &MemberLoc = BaseLoc->getChild(*Member);
333     if (MemberLoc.getType()->isReferenceType()) {
334       Env.setStorageLocation(*S, MemberLoc);
335     } else {
336       auto &Loc = Env.createStorageLocation(*S);
337       Env.setStorageLocation(*S, Loc);
338       Env.setValue(
339           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
340     }
341   }
342 
343   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
344     const Expr *InitExpr = S->getExpr();
345     assert(InitExpr != nullptr);
346 
347     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
348     if (InitExprVal == nullptr)
349       return;
350 
351     const FieldDecl *Field = S->getField();
352     assert(Field != nullptr);
353 
354     auto &ThisLoc =
355         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
356     auto &FieldLoc = ThisLoc.getChild(*Field);
357     Env.setValue(FieldLoc, *InitExprVal);
358   }
359 
360   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
361     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
362     assert(ConstructorDecl != nullptr);
363 
364     if (ConstructorDecl->isCopyOrMoveConstructor()) {
365       assert(S->getNumArgs() == 1);
366 
367       const Expr *Arg = S->getArg(0);
368       assert(Arg != nullptr);
369 
370       if (S->isElidable()) {
371         auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
372         if (ArgLoc == nullptr)
373           return;
374 
375         Env.setStorageLocation(*S, *ArgLoc);
376       } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
377         auto &Loc = Env.createStorageLocation(*S);
378         Env.setStorageLocation(*S, Loc);
379         Env.setValue(Loc, *ArgVal);
380       }
381       return;
382     }
383 
384     auto &Loc = Env.createStorageLocation(*S);
385     Env.setStorageLocation(*S, Loc);
386     if (Value *Val = Env.createValue(S->getType()))
387       Env.setValue(Loc, *Val);
388   }
389 
390   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
391     if (S->getOperator() == OO_Equal) {
392       assert(S->getNumArgs() == 2);
393 
394       const Expr *Arg0 = S->getArg(0);
395       assert(Arg0 != nullptr);
396 
397       const Expr *Arg1 = S->getArg(1);
398       assert(Arg1 != nullptr);
399 
400       // Evaluate only copy and move assignment operators.
401       auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
402       auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
403       if (Arg0Type != Arg1Type)
404         return;
405 
406       auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
407       if (ObjectLoc == nullptr)
408         return;
409 
410       auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
411       if (Val == nullptr)
412         return;
413 
414       // Assign a value to the storage location of the object.
415       Env.setValue(*ObjectLoc, *Val);
416 
417       // FIXME: Add a test for the value of the whole expression.
418       // Assign a storage location for the whole expression.
419       Env.setStorageLocation(*S, *ObjectLoc);
420     }
421   }
422 
423   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
424     if (S->getCastKind() == CK_ConstructorConversion) {
425       // The CFG does not contain `ParenExpr` as top-level statements in basic
426       // blocks, however sub-expressions can still be of that type.
427       assert(S->getSubExpr() != nullptr);
428       const Expr *SubExpr = S->getSubExpr();
429       assert(SubExpr != nullptr);
430 
431       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
432       if (SubExprLoc == nullptr)
433         return;
434 
435       Env.setStorageLocation(*S, *SubExprLoc);
436     }
437   }
438 
439   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
440     auto &Loc = Env.createStorageLocation(*S);
441     Env.setStorageLocation(*S, Loc);
442     if (Value *Val = Env.createValue(S->getType()))
443       Env.setValue(Loc, *Val);
444   }
445 
446   void VisitCallExpr(const CallExpr *S) {
447     if (S->isCallToStdMove()) {
448       assert(S->getNumArgs() == 1);
449 
450       const Expr *Arg = S->getArg(0);
451       assert(Arg != nullptr);
452 
453       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
454       if (ArgLoc == nullptr)
455         return;
456 
457       Env.setStorageLocation(*S, *ArgLoc);
458     }
459   }
460 
461   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
462     const Expr *SubExpr = S->getSubExpr();
463     assert(SubExpr != nullptr);
464 
465     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
466     if (SubExprLoc == nullptr)
467       return;
468 
469     Env.setStorageLocation(*S, *SubExprLoc);
470   }
471 
472   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
473     const Expr *SubExpr = S->getSubExpr();
474     assert(SubExpr != nullptr);
475 
476     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
477     if (SubExprLoc == nullptr)
478       return;
479 
480     Env.setStorageLocation(*S, *SubExprLoc);
481   }
482 
483   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
484     if (S->getCastKind() == CK_NoOp) {
485       const Expr *SubExpr = S->getSubExpr();
486       assert(SubExpr != nullptr);
487 
488       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
489       if (SubExprLoc == nullptr)
490         return;
491 
492       Env.setStorageLocation(*S, *SubExprLoc);
493     }
494   }
495 
496   void VisitConditionalOperator(const ConditionalOperator *S) {
497     // FIXME: Revisit this once flow conditions are added to the framework. For
498     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
499     // condition.
500     auto &Loc = Env.createStorageLocation(*S);
501     Env.setStorageLocation(*S, Loc);
502     if (Value *Val = Env.createValue(S->getType()))
503       Env.setValue(Loc, *Val);
504   }
505 
506   void VisitInitListExpr(const InitListExpr *S) {
507     QualType Type = S->getType();
508 
509     auto &Loc = Env.createStorageLocation(*S);
510     Env.setStorageLocation(*S, Loc);
511 
512     auto *Val = Env.createValue(Type);
513     if (Val == nullptr)
514       return;
515 
516     Env.setValue(Loc, *Val);
517 
518     if (Type->isStructureOrClassType()) {
519       for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
520         const FieldDecl *Field = std::get<0>(IT);
521         assert(Field != nullptr);
522 
523         const Expr *Init = std::get<1>(IT);
524         assert(Init != nullptr);
525 
526         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
527           cast<StructValue>(Val)->setChild(*Field, *InitVal);
528       }
529     }
530     // FIXME: Implement array initialization.
531   }
532 
533   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
534     auto &Loc = Env.createStorageLocation(*S);
535     Env.setStorageLocation(*S, Loc);
536     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
537   }
538 
539 private:
540   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
541     // `SubExpr` and its parent logic operator might be part of different basic
542     // blocks. We try to access the value that is assigned to `SubExpr` in the
543     // corresponding environment.
544     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
545       if (auto *Val = dyn_cast_or_null<BoolValue>(
546               SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
547         return *Val;
548     }
549 
550     // Sub-expressions that are logic operators are not added in basic blocks
551     // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
552     // operator, it isn't evaluated and assigned a value yet. In that case, we
553     // need to first visit `SubExpr` and then try to get the value that gets
554     // assigned to it.
555     Visit(&SubExpr);
556     if (auto *Val = dyn_cast_or_null<BoolValue>(
557             Env.getValue(SubExpr, SkipPast::Reference)))
558       return *Val;
559 
560     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
561     // boolean value for it.
562     return Env.makeAtomicBoolValue();
563   }
564 
565   const StmtToEnvMap &StmtToEnv;
566   Environment &Env;
567 };
568 
569 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
570   assert(!isa<ParenExpr>(&S));
571   TransferVisitor(StmtToEnv, Env).Visit(&S);
572 }
573 
574 } // namespace dataflow
575 } // namespace clang
576