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