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