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 static const Expr *skipExprWithCleanups(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 // The CFG does not contain `ParenExpr` as top-level statements in basic 159 // blocks, however sub-expressions can still be of that type. 160 InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens()); 161 assert(InitExpr != nullptr); 162 163 if (D.getType()->isReferenceType()) { 164 // Initializing a reference variable - do not create a reference to 165 // reference. 166 if (auto *InitExprLoc = 167 Env.getStorageLocation(*InitExpr, SkipPast::Reference)) { 168 auto &Val = 169 Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc)); 170 Env.setValue(Loc, Val); 171 } else { 172 // FIXME: The initializer expression must always be assigned a value. 173 // Replace this with an assert when we have sufficient coverage of 174 // language features. 175 if (Value *Val = Env.createValue(D.getType())) 176 Env.setValue(Loc, *Val); 177 } 178 return; 179 } 180 181 if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { 182 Env.setValue(Loc, *InitExprVal); 183 } else if (!D.getType()->isStructureOrClassType()) { 184 // FIXME: The initializer expression must always be assigned a value. 185 // Replace this with an assert when we have sufficient coverage of 186 // language features. 187 if (Value *Val = Env.createValue(D.getType())) 188 Env.setValue(Loc, *Val); 189 } else { 190 llvm_unreachable("structs and classes must always be assigned values"); 191 } 192 } 193 194 void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 195 // The CFG does not contain `ParenExpr` as top-level statements in basic 196 // blocks, however sub-expressions can still be of that type. 197 assert(S->getSubExpr() != nullptr); 198 const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); 199 assert(SubExpr != nullptr); 200 201 switch (S->getCastKind()) { 202 case CK_LValueToRValue: { 203 auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference); 204 if (SubExprVal == nullptr) 205 break; 206 207 auto &ExprLoc = Env.createStorageLocation(*S); 208 Env.setStorageLocation(*S, ExprLoc); 209 Env.setValue(ExprLoc, *SubExprVal); 210 break; 211 } 212 case CK_UncheckedDerivedToBase: 213 case CK_ConstructorConversion: 214 case CK_UserDefinedConversion: 215 // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 216 // CK_ConstructorConversion, and CK_UserDefinedConversion. 217 case CK_NoOp: { 218 // FIXME: Consider making `Environment::getStorageLocation` skip noop 219 // expressions (this and other similar expressions in the file) instead of 220 // assigning them storage locations. 221 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 222 if (SubExprLoc == nullptr) 223 break; 224 225 Env.setStorageLocation(*S, *SubExprLoc); 226 break; 227 } 228 default: 229 break; 230 } 231 } 232 233 void VisitUnaryOperator(const UnaryOperator *S) { 234 // The CFG does not contain `ParenExpr` as top-level statements in basic 235 // blocks, however sub-expressions can still be of that type. 236 assert(S->getSubExpr() != nullptr); 237 const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); 238 assert(SubExpr != nullptr); 239 240 switch (S->getOpcode()) { 241 case UO_Deref: { 242 // Skip past a reference to handle dereference of a dependent pointer. 243 const auto *SubExprVal = cast_or_null<PointerValue>( 244 Env.getValue(*SubExpr, SkipPast::Reference)); 245 if (SubExprVal == nullptr) 246 break; 247 248 auto &Loc = Env.createStorageLocation(*S); 249 Env.setStorageLocation(*S, Loc); 250 Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>( 251 SubExprVal->getPointeeLoc()))); 252 break; 253 } 254 case UO_AddrOf: { 255 // Do not form a pointer to a reference. If `SubExpr` is assigned a 256 // `ReferenceValue` then form a value that points to the location of its 257 // pointee. 258 StorageLocation *PointeeLoc = 259 Env.getStorageLocation(*SubExpr, SkipPast::Reference); 260 if (PointeeLoc == nullptr) 261 break; 262 263 auto &PointerLoc = Env.createStorageLocation(*S); 264 auto &PointerVal = 265 Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc)); 266 Env.setStorageLocation(*S, PointerLoc); 267 Env.setValue(PointerLoc, PointerVal); 268 break; 269 } 270 case UO_LNot: { 271 auto *SubExprVal = 272 dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None)); 273 if (SubExprVal == nullptr) 274 break; 275 276 auto &ExprLoc = Env.createStorageLocation(*S); 277 Env.setStorageLocation(*S, ExprLoc); 278 Env.setValue(ExprLoc, Env.makeNot(*SubExprVal)); 279 break; 280 } 281 default: 282 break; 283 } 284 } 285 286 void VisitCXXThisExpr(const CXXThisExpr *S) { 287 auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 288 assert(ThisPointeeLoc != nullptr); 289 290 auto &Loc = Env.createStorageLocation(*S); 291 Env.setStorageLocation(*S, Loc); 292 Env.setValue(Loc, Env.takeOwnership( 293 std::make_unique<PointerValue>(*ThisPointeeLoc))); 294 } 295 296 void VisitMemberExpr(const MemberExpr *S) { 297 ValueDecl *Member = S->getMemberDecl(); 298 assert(Member != nullptr); 299 300 // FIXME: Consider assigning pointer values to function member expressions. 301 if (Member->isFunctionOrFunctionTemplate()) 302 return; 303 304 if (auto *D = dyn_cast<VarDecl>(Member)) { 305 if (D->hasGlobalStorage()) { 306 auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); 307 if (VarDeclLoc == nullptr) 308 return; 309 310 if (VarDeclLoc->getType()->isReferenceType()) { 311 Env.setStorageLocation(*S, *VarDeclLoc); 312 } else { 313 auto &Loc = Env.createStorageLocation(*S); 314 Env.setStorageLocation(*S, Loc); 315 Env.setValue(Loc, Env.takeOwnership( 316 std::make_unique<ReferenceValue>(*VarDeclLoc))); 317 } 318 return; 319 } 320 } 321 322 // The receiver can be either a value or a pointer to a value. Skip past the 323 // indirection to handle both cases. 324 auto *BaseLoc = cast_or_null<AggregateStorageLocation>( 325 Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); 326 if (BaseLoc == nullptr) 327 return; 328 329 // FIXME: Add support for union types. 330 if (BaseLoc->getType()->isUnionType()) 331 return; 332 333 auto &MemberLoc = BaseLoc->getChild(*Member); 334 if (MemberLoc.getType()->isReferenceType()) { 335 Env.setStorageLocation(*S, MemberLoc); 336 } else { 337 auto &Loc = Env.createStorageLocation(*S); 338 Env.setStorageLocation(*S, Loc); 339 Env.setValue( 340 Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc))); 341 } 342 } 343 344 void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 345 const Expr *InitExpr = S->getExpr(); 346 assert(InitExpr != nullptr); 347 348 Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); 349 if (InitExprVal == nullptr) 350 return; 351 352 const FieldDecl *Field = S->getField(); 353 assert(Field != nullptr); 354 355 auto &ThisLoc = 356 *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); 357 auto &FieldLoc = ThisLoc.getChild(*Field); 358 Env.setValue(FieldLoc, *InitExprVal); 359 } 360 361 void VisitCXXConstructExpr(const CXXConstructExpr *S) { 362 const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 363 assert(ConstructorDecl != nullptr); 364 365 if (ConstructorDecl->isCopyOrMoveConstructor()) { 366 assert(S->getNumArgs() == 1); 367 368 const Expr *Arg = S->getArg(0); 369 assert(Arg != nullptr); 370 371 if (S->isElidable()) { 372 auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); 373 if (ArgLoc == nullptr) 374 return; 375 376 Env.setStorageLocation(*S, *ArgLoc); 377 } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) { 378 auto &Loc = Env.createStorageLocation(*S); 379 Env.setStorageLocation(*S, Loc); 380 Env.setValue(Loc, *ArgVal); 381 } 382 return; 383 } 384 385 auto &Loc = Env.createStorageLocation(*S); 386 Env.setStorageLocation(*S, Loc); 387 if (Value *Val = Env.createValue(S->getType())) 388 Env.setValue(Loc, *Val); 389 } 390 391 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 392 if (S->getOperator() == OO_Equal) { 393 assert(S->getNumArgs() == 2); 394 395 const Expr *Arg0 = S->getArg(0); 396 assert(Arg0 != nullptr); 397 398 const Expr *Arg1 = S->getArg(1); 399 assert(Arg1 != nullptr); 400 401 // Evaluate only copy and move assignment operators. 402 auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); 403 auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); 404 if (Arg0Type != Arg1Type) 405 return; 406 407 auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); 408 if (ObjectLoc == nullptr) 409 return; 410 411 auto *Val = Env.getValue(*Arg1, SkipPast::Reference); 412 if (Val == nullptr) 413 return; 414 415 // Assign a value to the storage location of the object. 416 Env.setValue(*ObjectLoc, *Val); 417 418 // FIXME: Add a test for the value of the whole expression. 419 // Assign a storage location for the whole expression. 420 Env.setStorageLocation(*S, *ObjectLoc); 421 } 422 } 423 424 void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 425 if (S->getCastKind() == CK_ConstructorConversion) { 426 // The CFG does not contain `ParenExpr` as top-level statements in basic 427 // blocks, however sub-expressions can still be of that type. 428 assert(S->getSubExpr() != nullptr); 429 const Expr *SubExpr = S->getSubExpr(); 430 assert(SubExpr != nullptr); 431 432 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 433 if (SubExprLoc == nullptr) 434 return; 435 436 Env.setStorageLocation(*S, *SubExprLoc); 437 } 438 } 439 440 void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 441 auto &Loc = Env.createStorageLocation(*S); 442 Env.setStorageLocation(*S, Loc); 443 if (Value *Val = Env.createValue(S->getType())) 444 Env.setValue(Loc, *Val); 445 } 446 447 void VisitCallExpr(const CallExpr *S) { 448 // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 449 // others (like trap, debugtrap, and unreachable) are handled by CFG 450 // construction. 451 if (S->isCallToStdMove()) { 452 assert(S->getNumArgs() == 1); 453 454 const Expr *Arg = S->getArg(0); 455 assert(Arg != nullptr); 456 457 auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); 458 if (ArgLoc == nullptr) 459 return; 460 461 Env.setStorageLocation(*S, *ArgLoc); 462 } else if (S->getDirectCallee() != nullptr && 463 S->getDirectCallee()->getBuiltinID() == 464 Builtin::BI__builtin_expect) { 465 assert(S->getNumArgs() > 0); 466 assert(S->getArg(0) != nullptr); 467 // `__builtin_expect` returns by-value, so strip away any potential 468 // references in the argument. 469 auto *ArgLoc = Env.getStorageLocation( 470 *S->getArg(0)->IgnoreParenImpCasts(), SkipPast::Reference); 471 if (ArgLoc == nullptr) 472 return; 473 Env.setStorageLocation(*S, *ArgLoc); 474 } 475 } 476 477 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 478 const Expr *SubExpr = S->getSubExpr(); 479 assert(SubExpr != nullptr); 480 481 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 482 if (SubExprLoc == nullptr) 483 return; 484 485 Env.setStorageLocation(*S, *SubExprLoc); 486 } 487 488 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 489 const Expr *SubExpr = S->getSubExpr(); 490 assert(SubExpr != nullptr); 491 492 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 493 if (SubExprLoc == nullptr) 494 return; 495 496 Env.setStorageLocation(*S, *SubExprLoc); 497 } 498 499 void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 500 if (S->getCastKind() == CK_NoOp) { 501 const Expr *SubExpr = S->getSubExpr(); 502 assert(SubExpr != nullptr); 503 504 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 505 if (SubExprLoc == nullptr) 506 return; 507 508 Env.setStorageLocation(*S, *SubExprLoc); 509 } 510 } 511 512 void VisitConditionalOperator(const ConditionalOperator *S) { 513 // FIXME: Revisit this once flow conditions are added to the framework. For 514 // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 515 // condition. 516 auto &Loc = Env.createStorageLocation(*S); 517 Env.setStorageLocation(*S, Loc); 518 if (Value *Val = Env.createValue(S->getType())) 519 Env.setValue(Loc, *Val); 520 } 521 522 void VisitInitListExpr(const InitListExpr *S) { 523 QualType Type = S->getType(); 524 525 auto &Loc = Env.createStorageLocation(*S); 526 Env.setStorageLocation(*S, Loc); 527 528 auto *Val = Env.createValue(Type); 529 if (Val == nullptr) 530 return; 531 532 Env.setValue(Loc, *Val); 533 534 if (Type->isStructureOrClassType()) { 535 for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) { 536 const FieldDecl *Field = std::get<0>(IT); 537 assert(Field != nullptr); 538 539 const Expr *Init = std::get<1>(IT); 540 assert(Init != nullptr); 541 542 if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) 543 cast<StructValue>(Val)->setChild(*Field, *InitVal); 544 } 545 } 546 // FIXME: Implement array initialization. 547 } 548 549 void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 550 auto &Loc = Env.createStorageLocation(*S); 551 Env.setStorageLocation(*S, Loc); 552 Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue())); 553 } 554 555 private: 556 BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 557 // `SubExpr` and its parent logic operator might be part of different basic 558 // blocks. We try to access the value that is assigned to `SubExpr` in the 559 // corresponding environment. 560 if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) { 561 if (auto *Val = dyn_cast_or_null<BoolValue>( 562 SubExprEnv->getValue(SubExpr, SkipPast::Reference))) 563 return *Val; 564 } 565 566 // Sub-expressions that are logic operators are not added in basic blocks 567 // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic 568 // operator, it isn't evaluated and assigned a value yet. In that case, we 569 // need to first visit `SubExpr` and then try to get the value that gets 570 // assigned to it. 571 Visit(&SubExpr); 572 if (auto *Val = dyn_cast_or_null<BoolValue>( 573 Env.getValue(SubExpr, SkipPast::Reference))) 574 return *Val; 575 576 // If the value of `SubExpr` is still unknown, we create a fresh symbolic 577 // boolean value for it. 578 return Env.makeAtomicBoolValue(); 579 } 580 581 const StmtToEnvMap &StmtToEnv; 582 Environment &Env; 583 }; 584 585 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 586 assert(!isa<ParenExpr>(&S)); 587 TransferVisitor(StmtToEnv, Env).Visit(&S); 588 } 589 590 } // namespace dataflow 591 } // namespace clang 592