907 lines · cpp
1//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// BodyFarm is a factory for creating faux implementations for functions/methods10// for analysis purposes.11//12//===----------------------------------------------------------------------===//13 14#include "clang/Analysis/BodyFarm.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/CXXInheritance.h"17#include "clang/AST/Decl.h"18#include "clang/AST/Expr.h"19#include "clang/AST/ExprCXX.h"20#include "clang/AST/ExprObjC.h"21#include "clang/AST/NestedNameSpecifier.h"22#include "clang/Analysis/CodeInjector.h"23#include "clang/Basic/Builtins.h"24#include "clang/Basic/OperatorKinds.h"25#include "llvm/ADT/StringSwitch.h"26#include "llvm/Support/Debug.h"27#include <optional>28 29#define DEBUG_TYPE "body-farm"30 31using namespace clang;32 33//===----------------------------------------------------------------------===//34// Helper creation functions for constructing faux ASTs.35//===----------------------------------------------------------------------===//36 37static bool isDispatchBlock(QualType Ty) {38 // Is it a block pointer?39 const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();40 if (!BPT)41 return false;42 43 // Check if the block pointer type takes no arguments and44 // returns void.45 const FunctionProtoType *FT =46 BPT->getPointeeType()->getAs<FunctionProtoType>();47 return FT && FT->getReturnType()->isVoidType() && FT->getNumParams() == 0;48}49 50namespace {51class ASTMaker {52public:53 ASTMaker(ASTContext &C) : C(C) {}54 55 /// Create a new BinaryOperator representing a simple assignment.56 BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);57 58 /// Create a new BinaryOperator representing a comparison.59 BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,60 BinaryOperator::Opcode Op);61 62 /// Create a new compound stmt using the provided statements.63 CompoundStmt *makeCompound(ArrayRef<Stmt*>);64 65 /// Create a new DeclRefExpr for the referenced variable.66 DeclRefExpr *makeDeclRefExpr(const VarDecl *D,67 bool RefersToEnclosingVariableOrCapture = false);68 69 /// Create a new UnaryOperator representing a dereference.70 UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);71 72 /// Create an implicit cast for an integer conversion.73 Expr *makeIntegralCast(const Expr *Arg, QualType Ty);74 75 /// Create an implicit cast to a builtin boolean type.76 ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);77 78 /// Create an implicit cast for lvalue-to-rvaluate conversions.79 ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);80 81 /// Make RValue out of variable declaration, creating a temporary82 /// DeclRefExpr in the process.83 ImplicitCastExpr *84 makeLvalueToRvalue(const VarDecl *Decl,85 bool RefersToEnclosingVariableOrCapture = false);86 87 /// Create an implicit cast of the given type.88 ImplicitCastExpr *makeImplicitCast(const Expr *Arg, QualType Ty,89 CastKind CK = CK_LValueToRValue);90 91 /// Create a cast to reference type.92 CastExpr *makeReferenceCast(const Expr *Arg, QualType Ty);93 94 /// Create an Objective-C bool literal.95 ObjCBoolLiteralExpr *makeObjCBool(bool Val);96 97 /// Create an Objective-C ivar reference.98 ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);99 100 /// Create a Return statement.101 ReturnStmt *makeReturn(const Expr *RetVal);102 103 /// Create an integer literal expression of the given type.104 IntegerLiteral *makeIntegerLiteral(uint64_t Value, QualType Ty);105 106 /// Create a member expression.107 MemberExpr *makeMemberExpression(Expr *base, ValueDecl *MemberDecl,108 bool IsArrow = false,109 ExprValueKind ValueKind = VK_LValue);110 111 /// Returns a *first* member field of a record declaration with a given name.112 /// \return an nullptr if no member with such a name exists.113 ValueDecl *findMemberField(const RecordDecl *RD, StringRef Name);114 115private:116 ASTContext &C;117};118}119 120BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,121 QualType Ty) {122 return BinaryOperator::Create(123 C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,124 VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());125}126 127BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,128 BinaryOperator::Opcode Op) {129 assert(BinaryOperator::isLogicalOp(Op) ||130 BinaryOperator::isComparisonOp(Op));131 return BinaryOperator::Create(132 C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), Op,133 C.getLogicalOperationType(), VK_PRValue, OK_Ordinary, SourceLocation(),134 FPOptionsOverride());135}136 137CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {138 return CompoundStmt::Create(C, Stmts, FPOptionsOverride(), SourceLocation(),139 SourceLocation());140}141 142DeclRefExpr *ASTMaker::makeDeclRefExpr(143 const VarDecl *D,144 bool RefersToEnclosingVariableOrCapture) {145 QualType Type = D->getType().getNonReferenceType();146 147 DeclRefExpr *DR = DeclRefExpr::Create(148 C, NestedNameSpecifierLoc(), SourceLocation(), const_cast<VarDecl *>(D),149 RefersToEnclosingVariableOrCapture, SourceLocation(), Type, VK_LValue);150 return DR;151}152 153UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {154 return UnaryOperator::Create(C, const_cast<Expr *>(Arg), UO_Deref, Ty,155 VK_LValue, OK_Ordinary, SourceLocation(),156 /*CanOverflow*/ false, FPOptionsOverride());157}158 159ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {160 return makeImplicitCast(Arg, Ty, CK_LValueToRValue);161}162 163ImplicitCastExpr *164ASTMaker::makeLvalueToRvalue(const VarDecl *Arg,165 bool RefersToEnclosingVariableOrCapture) {166 QualType Type = Arg->getType().getNonReferenceType();167 return makeLvalueToRvalue(makeDeclRefExpr(Arg,168 RefersToEnclosingVariableOrCapture),169 Type);170}171 172ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty,173 CastKind CK) {174 return ImplicitCastExpr::Create(C, Ty,175 /* CastKind=*/CK,176 /* Expr=*/const_cast<Expr *>(Arg),177 /* CXXCastPath=*/nullptr,178 /* ExprValueKind=*/VK_PRValue,179 /* FPFeatures */ FPOptionsOverride());180}181 182CastExpr *ASTMaker::makeReferenceCast(const Expr *Arg, QualType Ty) {183 assert(Ty->isReferenceType());184 return CXXStaticCastExpr::Create(185 C, Ty.getNonReferenceType(),186 Ty->isLValueReferenceType() ? VK_LValue : VK_XValue, CK_NoOp,187 const_cast<Expr *>(Arg), /*CXXCastPath=*/nullptr,188 /*Written=*/C.getTrivialTypeSourceInfo(Ty), FPOptionsOverride(),189 SourceLocation(), SourceLocation(), SourceRange());190}191 192Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {193 if (Arg->getType() == Ty)194 return const_cast<Expr*>(Arg);195 return makeImplicitCast(Arg, Ty, CK_IntegralCast);196}197 198ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {199 return makeImplicitCast(Arg, C.BoolTy, CK_IntegralToBoolean);200}201 202ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {203 QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;204 return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());205}206 207ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,208 const ObjCIvarDecl *IVar) {209 return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),210 IVar->getType(), SourceLocation(),211 SourceLocation(), const_cast<Expr*>(Base),212 /*arrow=*/true, /*free=*/false);213}214 215ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {216 return ReturnStmt::Create(C, SourceLocation(), const_cast<Expr *>(RetVal),217 /* NRVOCandidate=*/nullptr);218}219 220IntegerLiteral *ASTMaker::makeIntegerLiteral(uint64_t Value, QualType Ty) {221 llvm::APInt APValue = llvm::APInt(C.getTypeSize(Ty), Value);222 return IntegerLiteral::Create(C, APValue, Ty, SourceLocation());223}224 225MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,226 bool IsArrow,227 ExprValueKind ValueKind) {228 229 DeclAccessPair FoundDecl = DeclAccessPair::make(MemberDecl, AS_public);230 return MemberExpr::Create(231 C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),232 SourceLocation(), MemberDecl, FoundDecl,233 DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),234 /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,235 OK_Ordinary, NOUR_None);236}237 238ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {239 240 CXXBasePaths Paths(241 /* FindAmbiguities=*/false,242 /* RecordPaths=*/false,243 /* DetectVirtual=*/ false);244 const IdentifierInfo &II = C.Idents.get(Name);245 DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II);246 247 DeclContextLookupResult Decls = RD->lookup(DeclName);248 for (NamedDecl *FoundDecl : Decls)249 if (!FoundDecl->getDeclContext()->isFunctionOrMethod())250 return cast<ValueDecl>(FoundDecl);251 252 return nullptr;253}254 255//===----------------------------------------------------------------------===//256// Creation functions for faux ASTs.257//===----------------------------------------------------------------------===//258 259typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);260 261static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M,262 const ParmVarDecl *Callback,263 ArrayRef<Expr *> CallArgs) {264 265 QualType Ty = Callback->getType();266 DeclRefExpr *Call = M.makeDeclRefExpr(Callback);267 Expr *SubExpr;268 if (Ty->isRValueReferenceType()) {269 SubExpr = M.makeImplicitCast(270 Call, Ty.getNonReferenceType(), CK_LValueToRValue);271 } else if (Ty->isLValueReferenceType() &&272 Call->getType()->isFunctionType()) {273 Ty = C.getPointerType(Ty.getNonReferenceType());274 SubExpr = M.makeImplicitCast(Call, Ty, CK_FunctionToPointerDecay);275 } else if (Ty->isLValueReferenceType()276 && Call->getType()->isPointerType()277 && Call->getType()->getPointeeType()->isFunctionType()){278 SubExpr = Call;279 } else {280 llvm_unreachable("Unexpected state");281 }282 283 return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_PRValue,284 SourceLocation(), FPOptionsOverride());285}286 287static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,288 const ParmVarDecl *Callback,289 CXXRecordDecl *CallbackDecl,290 ArrayRef<Expr *> CallArgs) {291 assert(CallbackDecl != nullptr);292 assert(CallbackDecl->isLambda());293 FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator();294 assert(callOperatorDecl != nullptr);295 296 DeclRefExpr *callOperatorDeclRef = DeclRefExpr::Create(297 /* Ctx =*/C,298 /* QualifierLoc =*/NestedNameSpecifierLoc(),299 /* TemplateKWLoc =*/SourceLocation(), callOperatorDecl,300 /* RefersToEnclosingVariableOrCapture=*/false,301 /* NameLoc =*/SourceLocation(),302 /* T =*/callOperatorDecl->getType(),303 /* VK =*/VK_LValue);304 305 return CXXOperatorCallExpr::Create(306 /*AstContext=*/C, OO_Call, callOperatorDeclRef,307 /*Args=*/CallArgs,308 /*QualType=*/C.VoidTy,309 /*ExprValueType=*/VK_PRValue,310 /*SourceLocation=*/SourceLocation(),311 /*FPFeatures=*/FPOptionsOverride());312}313 314/// Create a fake body for 'std::move' or 'std::forward'. This is just:315///316/// \code317/// return static_cast<return_type>(param);318/// \endcode319static Stmt *create_std_move_forward(ASTContext &C, const FunctionDecl *D) {320 LLVM_DEBUG(llvm::dbgs() << "Generating body for std::move / std::forward\n");321 322 ASTMaker M(C);323 324 QualType ReturnType = D->getType()->castAs<FunctionType>()->getReturnType();325 Expr *Param = M.makeDeclRefExpr(D->getParamDecl(0));326 Expr *Cast = M.makeReferenceCast(Param, ReturnType);327 return M.makeReturn(Cast);328}329 330/// Create a fake body for std::call_once.331/// Emulates the following function body:332///333/// \code334/// typedef struct once_flag_s {335/// unsigned long __state = 0;336/// } once_flag;337/// template<class Callable>338/// void call_once(once_flag& o, Callable func) {339/// if (!o.__state) {340/// func();341/// }342/// o.__state = 1;343/// }344/// \endcode345static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {346 LLVM_DEBUG(llvm::dbgs() << "Generating body for call_once\n");347 348 // We need at least two parameters.349 if (D->param_size() < 2)350 return nullptr;351 352 ASTMaker M(C);353 354 const ParmVarDecl *Flag = D->getParamDecl(0);355 const ParmVarDecl *Callback = D->getParamDecl(1);356 357 if (!Callback->getType()->isReferenceType()) {358 llvm::dbgs() << "libcxx03 std::call_once implementation, skipping.\n";359 return nullptr;360 }361 if (!Flag->getType()->isReferenceType()) {362 llvm::dbgs() << "unknown std::call_once implementation, skipping.\n";363 return nullptr;364 }365 366 QualType CallbackType = Callback->getType().getNonReferenceType();367 368 // Nullable pointer, non-null iff function is a CXXRecordDecl.369 CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl();370 QualType FlagType = Flag->getType().getNonReferenceType();371 auto *FlagRecordDecl = FlagType->getAsRecordDecl();372 373 if (!FlagRecordDecl) {374 LLVM_DEBUG(llvm::dbgs() << "Flag field is not a record: "375 << "unknown std::call_once implementation, "376 << "ignoring the call.\n");377 return nullptr;378 }379 380 // We initially assume libc++ implementation of call_once,381 // where the once_flag struct has a field `__state_`.382 ValueDecl *FlagFieldDecl = M.findMemberField(FlagRecordDecl, "__state_");383 384 // Otherwise, try libstdc++ implementation, with a field385 // `_M_once`386 if (!FlagFieldDecl) {387 FlagFieldDecl = M.findMemberField(FlagRecordDecl, "_M_once");388 }389 390 if (!FlagFieldDecl) {391 LLVM_DEBUG(llvm::dbgs() << "No field _M_once or __state_ found on "392 << "std::once_flag struct: unknown std::call_once "393 << "implementation, ignoring the call.");394 return nullptr;395 }396 397 bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda();398 if (CallbackRecordDecl && !isLambdaCall) {399 LLVM_DEBUG(llvm::dbgs()400 << "Not supported: synthesizing body for functors when "401 << "body farming std::call_once, ignoring the call.");402 return nullptr;403 }404 405 SmallVector<Expr *, 5> CallArgs;406 const FunctionProtoType *CallbackFunctionType;407 if (isLambdaCall) {408 409 // Lambda requires callback itself inserted as a first parameter.410 CallArgs.push_back(411 M.makeDeclRefExpr(Callback,412 /* RefersToEnclosingVariableOrCapture=*/ true));413 CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator()414 ->getType()415 ->getAs<FunctionProtoType>();416 } else if (!CallbackType->getPointeeType().isNull()) {417 CallbackFunctionType =418 CallbackType->getPointeeType()->getAs<FunctionProtoType>();419 } else {420 CallbackFunctionType = CallbackType->getAs<FunctionProtoType>();421 }422 423 if (!CallbackFunctionType)424 return nullptr;425 426 // First two arguments are used for the flag and for the callback.427 if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) {428 LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "429 << "params passed to std::call_once, "430 << "ignoring the call\n");431 return nullptr;432 }433 434 // All arguments past first two ones are passed to the callback,435 // and we turn lvalues into rvalues if the argument is not passed by436 // reference.437 for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {438 const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);439 assert(PDecl);440 if (CallbackFunctionType->getParamType(ParamIdx - 2)441 .getNonReferenceType()442 .getCanonicalType() !=443 PDecl->getType().getNonReferenceType().getCanonicalType()) {444 LLVM_DEBUG(llvm::dbgs() << "Types of params of the callback do not match "445 << "params passed to std::call_once, "446 << "ignoring the call\n");447 return nullptr;448 }449 Expr *ParamExpr = M.makeDeclRefExpr(PDecl);450 if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) {451 QualType PTy = PDecl->getType().getNonReferenceType();452 ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy);453 }454 CallArgs.push_back(ParamExpr);455 }456 457 CallExpr *CallbackCall;458 if (isLambdaCall) {459 460 CallbackCall = create_call_once_lambda_call(C, M, Callback,461 CallbackRecordDecl, CallArgs);462 } else {463 464 // Function pointer case.465 CallbackCall = create_call_once_funcptr_call(C, M, Callback, CallArgs);466 }467 468 DeclRefExpr *FlagDecl =469 M.makeDeclRefExpr(Flag,470 /* RefersToEnclosingVariableOrCapture=*/true);471 472 473 MemberExpr *Deref = M.makeMemberExpression(FlagDecl, FlagFieldDecl);474 assert(Deref->isLValue());475 QualType DerefType = Deref->getType();476 477 // Negation predicate.478 UnaryOperator *FlagCheck = UnaryOperator::Create(479 C,480 /* input=*/481 M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType,482 CK_IntegralToBoolean),483 /* opc=*/UO_LNot,484 /* QualType=*/C.IntTy,485 /* ExprValueKind=*/VK_PRValue,486 /* ExprObjectKind=*/OK_Ordinary, SourceLocation(),487 /* CanOverflow*/ false, FPOptionsOverride());488 489 // Create assignment.490 BinaryOperator *FlagAssignment = M.makeAssignment(491 Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),492 DerefType);493 494 auto *Out =495 IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,496 /* Init=*/nullptr,497 /* Var=*/nullptr,498 /* Cond=*/FlagCheck,499 /* LPL=*/SourceLocation(),500 /* RPL=*/SourceLocation(),501 /* Then=*/M.makeCompound({CallbackCall, FlagAssignment}));502 503 return Out;504}505 506/// Create a fake body for dispatch_once.507static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {508 // Check if we have at least two parameters.509 if (D->param_size() != 2)510 return nullptr;511 512 // Check if the first parameter is a pointer to integer type.513 const ParmVarDecl *Predicate = D->getParamDecl(0);514 QualType PredicateQPtrTy = Predicate->getType();515 const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();516 if (!PredicatePtrTy)517 return nullptr;518 QualType PredicateTy = PredicatePtrTy->getPointeeType();519 if (!PredicateTy->isIntegerType())520 return nullptr;521 522 // Check if the second parameter is the proper block type.523 const ParmVarDecl *Block = D->getParamDecl(1);524 QualType Ty = Block->getType();525 if (!isDispatchBlock(Ty))526 return nullptr;527 528 // Everything checks out. Create a fakse body that checks the predicate,529 // sets it, and calls the block. Basically, an AST dump of:530 //531 // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {532 // if (*predicate != ~0l) {533 // *predicate = ~0l;534 // block();535 // }536 // }537 538 ASTMaker M(C);539 540 // (1) Create the call.541 CallExpr *CE = CallExpr::Create(542 /*ASTContext=*/C,543 /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),544 /*Args=*/{},545 /*QualType=*/C.VoidTy,546 /*ExprValueType=*/VK_PRValue,547 /*SourceLocation=*/SourceLocation(), FPOptionsOverride());548 549 // (2) Create the assignment to the predicate.550 Expr *DoneValue =551 UnaryOperator::Create(C, M.makeIntegerLiteral(0, C.LongTy), UO_Not,552 C.LongTy, VK_PRValue, OK_Ordinary, SourceLocation(),553 /*CanOverflow*/ false, FPOptionsOverride());554 555 BinaryOperator *B =556 M.makeAssignment(557 M.makeDereference(558 M.makeLvalueToRvalue(559 M.makeDeclRefExpr(Predicate), PredicateQPtrTy),560 PredicateTy),561 M.makeIntegralCast(DoneValue, PredicateTy),562 PredicateTy);563 564 // (3) Create the compound statement.565 Stmt *Stmts[] = { B, CE };566 CompoundStmt *CS = M.makeCompound(Stmts);567 568 // (4) Create the 'if' condition.569 ImplicitCastExpr *LValToRval =570 M.makeLvalueToRvalue(571 M.makeDereference(572 M.makeLvalueToRvalue(573 M.makeDeclRefExpr(Predicate),574 PredicateQPtrTy),575 PredicateTy),576 PredicateTy);577 578 Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);579 // (5) Create the 'if' statement.580 auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,581 /* Init=*/nullptr,582 /* Var=*/nullptr,583 /* Cond=*/GuardCondition,584 /* LPL=*/SourceLocation(),585 /* RPL=*/SourceLocation(),586 /* Then=*/CS);587 return If;588}589 590/// Create a fake body for dispatch_sync.591static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {592 // Check if we have at least two parameters.593 if (D->param_size() != 2)594 return nullptr;595 596 // Check if the second parameter is a block.597 const ParmVarDecl *PV = D->getParamDecl(1);598 QualType Ty = PV->getType();599 if (!isDispatchBlock(Ty))600 return nullptr;601 602 // Everything checks out. Create a fake body that just calls the block.603 // This is basically just an AST dump of:604 //605 // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {606 // block();607 // }608 //609 ASTMaker M(C);610 DeclRefExpr *DR = M.makeDeclRefExpr(PV);611 ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);612 CallExpr *CE = CallExpr::Create(C, ICE, {}, C.VoidTy, VK_PRValue,613 SourceLocation(), FPOptionsOverride());614 return CE;615}616 617static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)618{619 // There are exactly 3 arguments.620 if (D->param_size() != 3)621 return nullptr;622 623 // Signature:624 // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,625 // void *__newValue,626 // void * volatile *__theValue)627 // Generate body:628 // if (oldValue == *theValue) {629 // *theValue = newValue;630 // return YES;631 // }632 // else return NO;633 634 QualType ResultTy = D->getReturnType();635 bool isBoolean = ResultTy->isBooleanType();636 if (!isBoolean && !ResultTy->isIntegralType(C))637 return nullptr;638 639 const ParmVarDecl *OldValue = D->getParamDecl(0);640 QualType OldValueTy = OldValue->getType();641 642 const ParmVarDecl *NewValue = D->getParamDecl(1);643 QualType NewValueTy = NewValue->getType();644 645 assert(OldValueTy == NewValueTy);646 647 const ParmVarDecl *TheValue = D->getParamDecl(2);648 QualType TheValueTy = TheValue->getType();649 const PointerType *PT = TheValueTy->getAs<PointerType>();650 if (!PT)651 return nullptr;652 QualType PointeeTy = PT->getPointeeType();653 654 ASTMaker M(C);655 // Construct the comparison.656 Expr *Comparison =657 M.makeComparison(658 M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),659 M.makeLvalueToRvalue(660 M.makeDereference(661 M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),662 PointeeTy),663 PointeeTy),664 BO_EQ);665 666 // Construct the body of the IfStmt.667 Stmt *Stmts[2];668 Stmts[0] =669 M.makeAssignment(670 M.makeDereference(671 M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),672 PointeeTy),673 M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),674 NewValueTy);675 676 Expr *BoolVal = M.makeObjCBool(true);677 Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)678 : M.makeIntegralCast(BoolVal, ResultTy);679 Stmts[1] = M.makeReturn(RetVal);680 CompoundStmt *Body = M.makeCompound(Stmts);681 682 // Construct the else clause.683 BoolVal = M.makeObjCBool(false);684 RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)685 : M.makeIntegralCast(BoolVal, ResultTy);686 Stmt *Else = M.makeReturn(RetVal);687 688 /// Construct the If.689 auto *If =690 IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary,691 /* Init=*/nullptr,692 /* Var=*/nullptr, Comparison,693 /* LPL=*/SourceLocation(),694 /* RPL=*/SourceLocation(), Body, SourceLocation(), Else);695 696 return If;697}698 699Stmt *BodyFarm::getBody(const FunctionDecl *D) {700 std::optional<Stmt *> &Val = Bodies[D];701 if (Val)702 return *Val;703 704 Val = nullptr;705 706 if (D->getIdentifier() == nullptr)707 return nullptr;708 709 StringRef Name = D->getName();710 if (Name.empty())711 return nullptr;712 713 FunctionFarmer FF;714 715 if (unsigned BuiltinID = D->getBuiltinID()) {716 switch (BuiltinID) {717 case Builtin::BIas_const:718 case Builtin::BIforward:719 case Builtin::BIforward_like:720 case Builtin::BImove:721 case Builtin::BImove_if_noexcept:722 FF = create_std_move_forward;723 break;724 default:725 FF = nullptr;726 break;727 }728 } else if (Name.starts_with("OSAtomicCompareAndSwap") ||729 Name.starts_with("objc_atomicCompareAndSwap")) {730 FF = create_OSAtomicCompareAndSwap;731 } else if (Name == "call_once" && D->getDeclContext()->isStdNamespace()) {732 FF = create_call_once;733 } else {734 FF = llvm::StringSwitch<FunctionFarmer>(Name)735 .Case("dispatch_sync", create_dispatch_sync)736 .Case("dispatch_once", create_dispatch_once)737 .Default(nullptr);738 }739 740 if (FF) { Val = FF(C, D); }741 else if (Injector) { Val = Injector->getBody(D); }742 return *Val;743}744 745static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) {746 const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();747 748 if (IVar)749 return IVar;750 751 // When a readonly property is shadowed in a class extensions with a752 // a readwrite property, the instance variable belongs to the shadowing753 // property rather than the shadowed property. If there is no instance754 // variable on a readonly property, check to see whether the property is755 // shadowed and if so try to get the instance variable from shadowing756 // property.757 if (!Prop->isReadOnly())758 return nullptr;759 760 auto *Container = cast<ObjCContainerDecl>(Prop->getDeclContext());761 const ObjCInterfaceDecl *PrimaryInterface = nullptr;762 if (auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(Container)) {763 PrimaryInterface = InterfaceDecl;764 } else if (auto *CategoryDecl = dyn_cast<ObjCCategoryDecl>(Container)) {765 PrimaryInterface = CategoryDecl->getClassInterface();766 } else if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) {767 PrimaryInterface = ImplDecl->getClassInterface();768 } else {769 return nullptr;770 }771 772 // FindPropertyVisibleInPrimaryClass() looks first in class extensions, so it773 // is guaranteed to find the shadowing property, if it exists, rather than774 // the shadowed property.775 auto *ShadowingProp = PrimaryInterface->FindPropertyVisibleInPrimaryClass(776 Prop->getIdentifier(), Prop->getQueryKind());777 if (ShadowingProp && ShadowingProp != Prop) {778 IVar = ShadowingProp->getPropertyIvarDecl();779 }780 781 return IVar;782}783 784static Stmt *createObjCPropertyGetter(ASTContext &Ctx,785 const ObjCMethodDecl *MD) {786 // First, find the backing ivar.787 const ObjCIvarDecl *IVar = nullptr;788 const ObjCPropertyDecl *Prop = nullptr;789 790 // Property accessor stubs sometimes do not correspond to any property decl791 // in the current interface (but in a superclass). They still have a792 // corresponding property impl decl in this case.793 if (MD->isSynthesizedAccessorStub()) {794 const ObjCInterfaceDecl *IntD = MD->getClassInterface();795 const ObjCImplementationDecl *ImpD = IntD->getImplementation();796 for (const auto *PI : ImpD->property_impls()) {797 if (const ObjCPropertyDecl *Candidate = PI->getPropertyDecl()) {798 if (Candidate->getGetterName() == MD->getSelector()) {799 Prop = Candidate;800 IVar = Prop->getPropertyIvarDecl();801 }802 }803 }804 }805 806 if (!IVar) {807 Prop = MD->findPropertyDecl();808 IVar = Prop ? findBackingIvar(Prop) : nullptr;809 }810 811 if (!IVar || !Prop)812 return nullptr;813 814 // Ignore weak variables, which have special behavior.815 if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak)816 return nullptr;817 818 // Look to see if Sema has synthesized a body for us. This happens in819 // Objective-C++ because the return value may be a C++ class type with a820 // non-trivial copy constructor. We can only do this if we can find the821 // @synthesize for this property, though (or if we know it's been auto-822 // synthesized).823 const ObjCImplementationDecl *ImplDecl =824 IVar->getContainingInterface()->getImplementation();825 if (ImplDecl) {826 for (const auto *I : ImplDecl->property_impls()) {827 if (I->getPropertyDecl() != Prop)828 continue;829 830 if (I->getGetterCXXConstructor()) {831 ASTMaker M(Ctx);832 return M.makeReturn(I->getGetterCXXConstructor());833 }834 }835 }836 837 // We expect that the property is the same type as the ivar, or a reference to838 // it, and that it is either an object pointer or trivially copyable.839 if (!Ctx.hasSameUnqualifiedType(IVar->getType(),840 Prop->getType().getNonReferenceType()))841 return nullptr;842 if (!IVar->getType()->isObjCLifetimeType() &&843 !IVar->getType().isTriviallyCopyableType(Ctx))844 return nullptr;845 846 // Generate our body:847 // return self->_ivar;848 ASTMaker M(Ctx);849 850 const VarDecl *selfVar = MD->getSelfDecl();851 if (!selfVar)852 return nullptr;853 854 Expr *loadedIVar = M.makeObjCIvarRef(855 M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()),856 IVar);857 858 if (!MD->getReturnType()->isReferenceType())859 loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());860 861 return M.makeReturn(loadedIVar);862}863 864Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {865 // We currently only know how to synthesize property accessors.866 if (!D->isPropertyAccessor())867 return nullptr;868 869 D = D->getCanonicalDecl();870 871 // We should not try to synthesize explicitly redefined accessors.872 // We do not know for sure how they behave.873 if (!D->isImplicit())874 return nullptr;875 876 std::optional<Stmt *> &Val = Bodies[D];877 if (Val)878 return *Val;879 Val = nullptr;880 881 // For now, we only synthesize getters.882 // Synthesizing setters would cause false negatives in the883 // RetainCountChecker because the method body would bind the parameter884 // to an instance variable, causing it to escape. This would prevent885 // warning in the following common scenario:886 //887 // id foo = [[NSObject alloc] init];888 // self.foo = foo; // We should warn that foo leaks here.889 //890 if (D->param_size() != 0)891 return nullptr;892 893 // If the property was defined in an extension, search the extensions for894 // overrides.895 const ObjCInterfaceDecl *OID = D->getClassInterface();896 if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID)897 for (auto *Ext : OID->known_extensions()) {898 auto *OMD = Ext->getInstanceMethod(D->getSelector());899 if (OMD && !OMD->isImplicit())900 return nullptr;901 }902 903 Val = createObjCPropertyGetter(C, D);904 905 return *Val;906}907