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/ControlFlowContext.h" 24 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 25 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" 26 #include "clang/Analysis/FlowSensitive/RecordOps.h" 27 #include "clang/Analysis/FlowSensitive/Value.h" 28 #include "clang/Basic/Builtins.h" 29 #include "clang/Basic/OperatorKinds.h" 30 #include "llvm/ADT/STLExtras.h" 31 #include "llvm/Support/Casting.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include <cassert> 34 #include <memory> 35 #include <tuple> 36 37 namespace clang { 38 namespace dataflow { 39 40 const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { 41 auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); 42 assert(BlockIt != CFCtx.getStmtToBlock().end()); 43 if (!CFCtx.isBlockReachable(*BlockIt->getSecond())) 44 return nullptr; 45 const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; 46 assert(State); 47 return &State->Env; 48 } 49 50 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 51 Environment &Env) { 52 Value *LHSValue = Env.getValueStrict(LHS); 53 Value *RHSValue = Env.getValueStrict(RHS); 54 55 if (LHSValue == RHSValue) 56 return Env.getBoolLiteralValue(true); 57 58 if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue)) 59 if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue)) 60 return Env.makeIff(*LHSBool, *RHSBool); 61 62 return Env.makeAtomicBoolValue(); 63 } 64 65 static BoolValue &unpackValue(BoolValue &V, Environment &Env) { 66 if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) { 67 auto &A = Env.getDataflowAnalysisContext().arena(); 68 return A.makeBoolValue(A.makeAtomRef(Top->getAtom())); 69 } 70 return V; 71 } 72 73 // Unpacks the value (if any) associated with `E` and updates `E` to the new 74 // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion, 75 // by skipping past the reference. 76 static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { 77 auto *Loc = Env.getStorageLocationStrict(E); 78 if (Loc == nullptr) 79 return nullptr; 80 auto *Val = Env.getValue(*Loc); 81 82 auto *B = dyn_cast_or_null<BoolValue>(Val); 83 if (B == nullptr) 84 return Val; 85 86 auto &UnpackedVal = unpackValue(*B, Env); 87 if (&UnpackedVal == Val) 88 return Val; 89 Env.setValue(*Loc, UnpackedVal); 90 return &UnpackedVal; 91 } 92 93 static void propagateValue(const Expr &From, const Expr &To, Environment &Env) { 94 if (auto *Val = Env.getValueStrict(From)) 95 Env.setValueStrict(To, *Val); 96 } 97 98 static void propagateStorageLocation(const Expr &From, const Expr &To, 99 Environment &Env) { 100 if (auto *Loc = Env.getStorageLocationStrict(From)) 101 Env.setStorageLocationStrict(To, *Loc); 102 } 103 104 // Propagates the value or storage location of `From` to `To` in cases where 105 // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff 106 // `From` is a glvalue. 107 static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, 108 Environment &Env) { 109 assert(From.isGLValue() == To.isGLValue()); 110 if (From.isGLValue()) 111 propagateStorageLocation(From, To, Env); 112 else 113 propagateValue(From, To, Env); 114 } 115 116 namespace { 117 118 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 119 public: 120 TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) 121 : StmtToEnv(StmtToEnv), Env(Env) {} 122 123 void VisitBinaryOperator(const BinaryOperator *S) { 124 const Expr *LHS = S->getLHS(); 125 assert(LHS != nullptr); 126 127 const Expr *RHS = S->getRHS(); 128 assert(RHS != nullptr); 129 130 switch (S->getOpcode()) { 131 case BO_Assign: { 132 auto *LHSLoc = Env.getStorageLocationStrict(*LHS); 133 if (LHSLoc == nullptr) 134 break; 135 136 auto *RHSVal = Env.getValueStrict(*RHS); 137 if (RHSVal == nullptr) 138 break; 139 140 // Assign a value to the storage location of the left-hand side. 141 Env.setValue(*LHSLoc, *RHSVal); 142 143 // Assign a storage location for the whole expression. 144 Env.setStorageLocation(*S, *LHSLoc); 145 break; 146 } 147 case BO_LAnd: 148 case BO_LOr: { 149 auto &Loc = Env.createStorageLocation(*S); 150 Env.setStorageLocation(*S, Loc); 151 152 BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 153 BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 154 155 if (S->getOpcode() == BO_LAnd) 156 Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal)); 157 else 158 Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal)); 159 break; 160 } 161 case BO_NE: 162 case BO_EQ: { 163 auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 164 auto &Loc = Env.createStorageLocation(*S); 165 Env.setStorageLocation(*S, Loc); 166 Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue 167 : Env.makeNot(LHSEqRHSValue)); 168 break; 169 } 170 case BO_Comma: { 171 propagateValueOrStorageLocation(*RHS, *S, Env); 172 break; 173 } 174 default: 175 break; 176 } 177 } 178 179 void VisitDeclRefExpr(const DeclRefExpr *S) { 180 const ValueDecl *VD = S->getDecl(); 181 assert(VD != nullptr); 182 183 // `DeclRefExpr`s to fields and non-static methods aren't glvalues, and 184 // there's also no sensible `Value` we can assign to them, so skip them. 185 if (isa<FieldDecl>(VD)) 186 return; 187 if (auto *Method = dyn_cast<CXXMethodDecl>(VD); 188 Method && !Method->isStatic()) 189 return; 190 191 auto *DeclLoc = Env.getStorageLocation(*VD); 192 if (DeclLoc == nullptr) 193 return; 194 195 Env.setStorageLocationStrict(*S, *DeclLoc); 196 } 197 198 void VisitDeclStmt(const DeclStmt *S) { 199 // Group decls are converted into single decls in the CFG so the cast below 200 // is safe. 201 const auto &D = *cast<VarDecl>(S->getSingleDecl()); 202 203 ProcessVarDecl(D); 204 } 205 206 void ProcessVarDecl(const VarDecl &D) { 207 // Static local vars are already initialized in `Environment`. 208 if (D.hasGlobalStorage()) 209 return; 210 211 // If this is the holding variable for a `BindingDecl`, we may already 212 // have a storage location set up -- so check. (See also explanation below 213 // where we process the `BindingDecl`.) 214 if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr) 215 return; 216 217 assert(Env.getStorageLocation(D) == nullptr); 218 219 Env.setStorageLocation(D, Env.createObject(D)); 220 221 // `DecompositionDecl` must be handled after we've interpreted the loc 222 // itself, because the binding expression refers back to the 223 // `DecompositionDecl` (even though it has no written name). 224 if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 225 // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 226 // needs to be evaluated after initializing the values in the storage for 227 // VarDecl, as the bindings refer to them. 228 // FIXME: Add support for ArraySubscriptExpr. 229 // FIXME: Consider adding AST nodes used in BindingDecls to the CFG. 230 for (const auto *B : Decomp->bindings()) { 231 if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) { 232 auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 233 if (DE == nullptr) 234 continue; 235 236 // ME and its base haven't been visited because they aren't included 237 // in the statements of the CFG basic block. 238 VisitDeclRefExpr(DE); 239 VisitMemberExpr(ME); 240 241 if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference)) 242 Env.setStorageLocation(*B, *Loc); 243 } else if (auto *VD = B->getHoldingVar()) { 244 // Holding vars are used to back the `BindingDecl`s of tuple-like 245 // types. The holding var declarations appear after the 246 // `DecompositionDecl`, so we have to explicitly process them here 247 // to know their storage location. They will be processed a second 248 // time when we visit their `VarDecl`s, so we have code that protects 249 // against this above. 250 ProcessVarDecl(*VD); 251 auto *VDLoc = Env.getStorageLocation(*VD); 252 assert(VDLoc != nullptr); 253 Env.setStorageLocation(*B, *VDLoc); 254 } 255 } 256 } 257 } 258 259 void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 260 const Expr *SubExpr = S->getSubExpr(); 261 assert(SubExpr != nullptr); 262 263 switch (S->getCastKind()) { 264 case CK_IntegralToBoolean: { 265 // This cast creates a new, boolean value from the integral value. We 266 // model that with a fresh value in the environment, unless it's already a 267 // boolean. 268 if (auto *SubExprVal = 269 dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr))) 270 Env.setValueStrict(*S, *SubExprVal); 271 else 272 // FIXME: If integer modeling is added, then update this code to create 273 // the boolean based on the integer model. 274 Env.setValueStrict(*S, Env.makeAtomicBoolValue()); 275 break; 276 } 277 278 case CK_LValueToRValue: { 279 // When an L-value is used as an R-value, it may result in sharing, so we 280 // need to unpack any nested `Top`s. We also need to strip off the 281 // `ReferenceValue` associated with the lvalue. 282 auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); 283 if (SubExprVal == nullptr) 284 break; 285 286 auto &ExprLoc = Env.createStorageLocation(*S); 287 Env.setStorageLocation(*S, ExprLoc); 288 Env.setValue(ExprLoc, *SubExprVal); 289 break; 290 } 291 292 case CK_IntegralCast: 293 // FIXME: This cast creates a new integral value from the 294 // subexpression. But, because we don't model integers, we don't 295 // distinguish between this new value and the underlying one. If integer 296 // modeling is added, then update this code to create a fresh location and 297 // value. 298 case CK_UncheckedDerivedToBase: 299 case CK_ConstructorConversion: 300 case CK_UserDefinedConversion: 301 // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 302 // CK_ConstructorConversion, and CK_UserDefinedConversion. 303 case CK_NoOp: { 304 // FIXME: Consider making `Environment::getStorageLocation` skip noop 305 // expressions (this and other similar expressions in the file) instead 306 // of assigning them storage locations. 307 propagateValueOrStorageLocation(*SubExpr, *S, Env); 308 break; 309 } 310 case CK_NullToPointer: { 311 auto &Loc = Env.createStorageLocation(S->getType()); 312 Env.setStorageLocation(*S, Loc); 313 314 auto &NullPointerVal = 315 Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 316 Env.setValue(Loc, NullPointerVal); 317 break; 318 } 319 case CK_NullToMemberPointer: 320 // FIXME: Implement pointers to members. For now, don't associate a value 321 // with this expression. 322 break; 323 case CK_FunctionToPointerDecay: { 324 StorageLocation *PointeeLoc = 325 Env.getStorageLocation(*SubExpr, SkipPast::Reference); 326 if (PointeeLoc == nullptr) 327 break; 328 329 auto &PointerLoc = Env.createStorageLocation(*S); 330 auto &PointerVal = Env.create<PointerValue>(*PointeeLoc); 331 Env.setStorageLocation(*S, PointerLoc); 332 Env.setValue(PointerLoc, PointerVal); 333 break; 334 } 335 case CK_BuiltinFnToFnPtr: 336 // Despite its name, the result type of `BuiltinFnToFnPtr` is a function, 337 // not a function pointer. In addition, builtin functions can only be 338 // called directly; it is not legal to take their address. We therefore 339 // don't need to create a value or storage location for them. 340 break; 341 default: 342 break; 343 } 344 } 345 346 void VisitUnaryOperator(const UnaryOperator *S) { 347 const Expr *SubExpr = S->getSubExpr(); 348 assert(SubExpr != nullptr); 349 350 switch (S->getOpcode()) { 351 case UO_Deref: { 352 const auto *SubExprVal = 353 cast_or_null<PointerValue>(Env.getValueStrict(*SubExpr)); 354 if (SubExprVal == nullptr) 355 break; 356 357 Env.setStorageLocationStrict(*S, SubExprVal->getPointeeLoc()); 358 break; 359 } 360 case UO_AddrOf: { 361 // FIXME: Model pointers to members. 362 if (S->getType()->isMemberPointerType()) 363 break; 364 365 if (StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr)) 366 Env.setValueStrict(*S, Env.create<PointerValue>(*PointeeLoc)); 367 break; 368 } 369 case UO_LNot: { 370 auto *SubExprVal = 371 dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr)); 372 if (SubExprVal == nullptr) 373 break; 374 375 auto &ExprLoc = Env.createStorageLocation(*S); 376 Env.setStorageLocation(*S, ExprLoc); 377 Env.setValue(ExprLoc, Env.makeNot(*SubExprVal)); 378 break; 379 } 380 default: 381 break; 382 } 383 } 384 385 void VisitCXXThisExpr(const CXXThisExpr *S) { 386 auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 387 if (ThisPointeeLoc == nullptr) 388 // Unions are not supported yet, and will not have a location for the 389 // `this` expression's pointee. 390 return; 391 392 auto &Loc = Env.createStorageLocation(*S); 393 Env.setStorageLocation(*S, Loc); 394 Env.setValue(Loc, Env.create<PointerValue>(*ThisPointeeLoc)); 395 } 396 397 void VisitCXXNewExpr(const CXXNewExpr *S) { 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 VisitCXXDeleteExpr(const CXXDeleteExpr *S) { 405 // Empty method. 406 // We consciously don't do anything on deletes. Diagnosing double deletes 407 // (for example) should be done by a specific analysis, not by the 408 // framework. 409 } 410 411 void VisitReturnStmt(const ReturnStmt *S) { 412 if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts) 413 return; 414 415 auto *Ret = S->getRetValue(); 416 if (Ret == nullptr) 417 return; 418 419 if (Ret->isPRValue()) { 420 auto *Val = Env.getValueStrict(*Ret); 421 if (Val == nullptr) 422 return; 423 424 // FIXME: Model NRVO. 425 Env.setReturnValue(Val); 426 } else { 427 auto *Loc = Env.getStorageLocationStrict(*Ret); 428 if (Loc == nullptr) 429 return; 430 431 // FIXME: Model NRVO. 432 Env.setReturnStorageLocation(Loc); 433 } 434 } 435 436 void VisitMemberExpr(const MemberExpr *S) { 437 ValueDecl *Member = S->getMemberDecl(); 438 assert(Member != nullptr); 439 440 // FIXME: Consider assigning pointer values to function member expressions. 441 if (Member->isFunctionOrFunctionTemplate()) 442 return; 443 444 // FIXME: if/when we add support for modeling enums, use that support here. 445 if (isa<EnumConstantDecl>(Member)) 446 return; 447 448 if (auto *D = dyn_cast<VarDecl>(Member)) { 449 if (D->hasGlobalStorage()) { 450 auto *VarDeclLoc = Env.getStorageLocation(*D); 451 if (VarDeclLoc == nullptr) 452 return; 453 454 Env.setStorageLocation(*S, *VarDeclLoc); 455 return; 456 } 457 } 458 459 AggregateStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); 460 if (BaseLoc == nullptr) 461 return; 462 463 auto *MemberLoc = BaseLoc->getChild(*Member); 464 if (MemberLoc == nullptr) 465 return; 466 Env.setStorageLocationStrict(*S, *MemberLoc); 467 } 468 469 void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 470 const Expr *InitExpr = S->getExpr(); 471 assert(InitExpr != nullptr); 472 propagateValueOrStorageLocation(*InitExpr, *S, Env); 473 } 474 475 void VisitCXXConstructExpr(const CXXConstructExpr *S) { 476 const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 477 assert(ConstructorDecl != nullptr); 478 479 if (ConstructorDecl->isCopyOrMoveConstructor()) { 480 // It is permissible for a copy/move constructor to have additional 481 // parameters as long as they have default arguments defined for them. 482 assert(S->getNumArgs() != 0); 483 484 const Expr *Arg = S->getArg(0); 485 assert(Arg != nullptr); 486 487 auto *ArgLoc = cast_or_null<AggregateStorageLocation>( 488 Env.getStorageLocation(*Arg, SkipPast::Reference)); 489 if (ArgLoc == nullptr) 490 return; 491 492 if (S->isElidable()) { 493 Env.setStorageLocation(*S, *ArgLoc); 494 } else if (auto *ArgVal = cast_or_null<StructValue>( 495 Env.getValue(*Arg, SkipPast::Reference))) { 496 auto &Val = *cast<StructValue>(Env.createValue(S->getType())); 497 Env.setValueStrict(*S, Val); 498 copyRecord(ArgVal->getAggregateLoc(), Val.getAggregateLoc(), Env); 499 } 500 return; 501 } 502 503 auto &InitialVal = *cast<StructValue>(Env.createValue(S->getType())); 504 copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S), 505 Env); 506 507 transferInlineCall(S, ConstructorDecl); 508 } 509 510 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 511 if (S->getOperator() == OO_Equal) { 512 assert(S->getNumArgs() == 2); 513 514 const Expr *Arg0 = S->getArg(0); 515 assert(Arg0 != nullptr); 516 517 const Expr *Arg1 = S->getArg(1); 518 assert(Arg1 != nullptr); 519 520 // Evaluate only copy and move assignment operators. 521 const auto *Method = 522 dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee()); 523 if (!Method) 524 return; 525 if (!Method->isCopyAssignmentOperator() && 526 !Method->isMoveAssignmentOperator()) 527 return; 528 529 auto *LocSrc = cast_or_null<AggregateStorageLocation>( 530 Env.getStorageLocationStrict(*Arg1)); 531 auto *LocDst = cast_or_null<AggregateStorageLocation>( 532 Env.getStorageLocationStrict(*Arg0)); 533 534 if (LocSrc != nullptr && LocDst != nullptr) { 535 copyRecord(*LocSrc, *LocDst, Env); 536 Env.setStorageLocationStrict(*S, *LocDst); 537 } 538 } 539 } 540 541 void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 542 if (S->getCastKind() == CK_ConstructorConversion) { 543 const Expr *SubExpr = S->getSubExpr(); 544 assert(SubExpr != nullptr); 545 546 propagateValue(*SubExpr, *S, Env); 547 } 548 } 549 550 void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 551 if (Value *Val = Env.createValue(S->getType())) 552 Env.setValueStrict(*S, *Val); 553 } 554 555 void VisitCallExpr(const CallExpr *S) { 556 // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 557 // others (like trap, debugtrap, and unreachable) are handled by CFG 558 // construction. 559 if (S->isCallToStdMove()) { 560 assert(S->getNumArgs() == 1); 561 562 const Expr *Arg = S->getArg(0); 563 assert(Arg != nullptr); 564 565 auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); 566 if (ArgLoc == nullptr) 567 return; 568 569 Env.setStorageLocation(*S, *ArgLoc); 570 } else if (S->getDirectCallee() != nullptr && 571 S->getDirectCallee()->getBuiltinID() == 572 Builtin::BI__builtin_expect) { 573 assert(S->getNumArgs() > 0); 574 assert(S->getArg(0) != nullptr); 575 // `__builtin_expect` returns by-value, so strip away any potential 576 // references in the argument. 577 auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference); 578 if (ArgLoc == nullptr) 579 return; 580 Env.setStorageLocation(*S, *ArgLoc); 581 } else if (const FunctionDecl *F = S->getDirectCallee()) { 582 transferInlineCall(S, F); 583 } 584 } 585 586 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 587 const Expr *SubExpr = S->getSubExpr(); 588 assert(SubExpr != nullptr); 589 590 Value *SubExprVal = Env.getValueStrict(*SubExpr); 591 if (SubExprVal == nullptr) 592 return; 593 594 if (StructValue *StructVal = dyn_cast<StructValue>(SubExprVal)) { 595 Env.setStorageLocation(*S, StructVal->getAggregateLoc()); 596 return; 597 } 598 599 StorageLocation &Loc = Env.createStorageLocation(*S); 600 Env.setValue(Loc, *SubExprVal); 601 Env.setStorageLocation(*S, Loc); 602 } 603 604 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 605 const Expr *SubExpr = S->getSubExpr(); 606 assert(SubExpr != nullptr); 607 608 propagateValue(*SubExpr, *S, Env); 609 } 610 611 void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 612 if (S->getCastKind() == CK_NoOp) { 613 const Expr *SubExpr = S->getSubExpr(); 614 assert(SubExpr != nullptr); 615 616 propagateValueOrStorageLocation(*SubExpr, *S, Env); 617 } 618 } 619 620 void VisitConditionalOperator(const ConditionalOperator *S) { 621 // FIXME: Revisit this once flow conditions are added to the framework. For 622 // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 623 // condition. 624 if (S->isGLValue()) 625 Env.setStorageLocationStrict(*S, Env.createObject(S->getType())); 626 else if (Value *Val = Env.createValue(S->getType())) 627 Env.setValueStrict(*S, *Val); 628 } 629 630 void VisitInitListExpr(const InitListExpr *S) { 631 QualType Type = S->getType(); 632 633 if (!Type->isStructureOrClassType()) { 634 if (auto *Val = Env.createValue(Type)) 635 Env.setValueStrict(*S, *Val); 636 637 return; 638 } 639 640 std::vector<FieldDecl *> Fields = 641 getFieldsForInitListExpr(Type->getAsRecordDecl()); 642 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 643 644 for (auto [Field, Init] : llvm::zip(Fields, S->inits())) { 645 assert(Field != nullptr); 646 assert(Init != nullptr); 647 648 FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)}); 649 } 650 651 auto &Loc = 652 Env.getDataflowAnalysisContext() 653 .arena() 654 .create<AggregateStorageLocation>(Type, std::move(FieldLocs)); 655 StructValue &StructVal = Env.create<StructValue>(Loc); 656 657 Env.setValue(Loc, StructVal); 658 659 Env.setValueStrict(*S, StructVal); 660 661 // FIXME: Implement array initialization. 662 } 663 664 void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 665 Env.setValueStrict(*S, Env.getBoolLiteralValue(S->getValue())); 666 } 667 668 void VisitIntegerLiteral(const IntegerLiteral *S) { 669 Env.setValueStrict(*S, Env.getIntLiteralValue(S->getValue())); 670 } 671 672 void VisitParenExpr(const ParenExpr *S) { 673 // The CFG does not contain `ParenExpr` as top-level statements in basic 674 // blocks, however manual traversal to sub-expressions may encounter them. 675 // Redirect to the sub-expression. 676 auto *SubExpr = S->getSubExpr(); 677 assert(SubExpr != nullptr); 678 Visit(SubExpr); 679 } 680 681 void VisitExprWithCleanups(const ExprWithCleanups *S) { 682 // The CFG does not contain `ExprWithCleanups` as top-level statements in 683 // basic blocks, however manual traversal to sub-expressions may encounter 684 // them. Redirect to the sub-expression. 685 auto *SubExpr = S->getSubExpr(); 686 assert(SubExpr != nullptr); 687 Visit(SubExpr); 688 } 689 690 private: 691 /// Returns the value for the sub-expression `SubExpr` of a logic operator. 692 BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 693 // `SubExpr` and its parent logic operator might be part of different basic 694 // blocks. We try to access the value that is assigned to `SubExpr` in the 695 // corresponding environment. 696 if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) 697 if (auto *Val = 698 dyn_cast_or_null<BoolValue>(SubExprEnv->getValueStrict(SubExpr))) 699 return *Val; 700 701 // The sub-expression may lie within a basic block that isn't reachable, 702 // even if we need it to evaluate the current (reachable) expression 703 // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` 704 // within the current environment and then try to get the value that gets 705 // assigned to it. 706 if (Env.getValueStrict(SubExpr) == nullptr) 707 Visit(&SubExpr); 708 if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValueStrict(SubExpr))) 709 return *Val; 710 711 // If the value of `SubExpr` is still unknown, we create a fresh symbolic 712 // boolean value for it. 713 return Env.makeAtomicBoolValue(); 714 } 715 716 // If context sensitivity is enabled, try to analyze the body of the callee 717 // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 718 template <typename E> 719 void transferInlineCall(const E *S, const FunctionDecl *F) { 720 const auto &Options = Env.getDataflowAnalysisContext().getOptions(); 721 if (!(Options.ContextSensitiveOpts && 722 Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 723 return; 724 725 const ControlFlowContext *CFCtx = 726 Env.getDataflowAnalysisContext().getControlFlowContext(F); 727 if (!CFCtx) 728 return; 729 730 // FIXME: We don't support context-sensitive analysis of recursion, so 731 // we should return early here if `F` is the same as the `FunctionDecl` 732 // holding `S` itself. 733 734 auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); 735 736 auto CalleeEnv = Env.pushCall(S); 737 738 // FIXME: Use the same analysis as the caller for the callee. Note, 739 // though, that doing so would require support for changing the analysis's 740 // ASTContext. 741 assert(CFCtx->getDecl() != nullptr && 742 "ControlFlowContexts in the environment should always carry a decl"); 743 auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(), 744 DataflowAnalysisOptions{Options}); 745 746 auto BlockToOutputState = 747 dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); 748 assert(BlockToOutputState); 749 assert(ExitBlock < BlockToOutputState->size()); 750 751 auto &ExitState = (*BlockToOutputState)[ExitBlock]; 752 assert(ExitState); 753 754 Env.popCall(S, ExitState->Env); 755 } 756 757 const StmtToEnvMap &StmtToEnv; 758 Environment &Env; 759 }; 760 761 } // namespace 762 763 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 764 TransferVisitor(StmtToEnv, Env).Visit(&S); 765 } 766 767 } // namespace dataflow 768 } // namespace clang 769