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