Home | History | Annotate | Download | only in Analysis
      1 //== BodyFarm.cpp  - Factory for conjuring up fake bodies ----------*- C++ -*-//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // BodyFarm is a factory for creating faux implementations for functions/methods
     11 // for analysis purposes.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "BodyFarm.h"
     16 #include "clang/AST/ASTContext.h"
     17 #include "clang/AST/Decl.h"
     18 #include "clang/AST/Expr.h"
     19 #include "clang/AST/ExprObjC.h"
     20 #include "llvm/ADT/StringSwitch.h"
     21 
     22 using namespace clang;
     23 
     24 //===----------------------------------------------------------------------===//
     25 // Helper creation functions for constructing faux ASTs.
     26 //===----------------------------------------------------------------------===//
     27 
     28 static bool isDispatchBlock(QualType Ty) {
     29   // Is it a block pointer?
     30   const BlockPointerType *BPT = Ty->getAs<BlockPointerType>();
     31   if (!BPT)
     32     return false;
     33 
     34   // Check if the block pointer type takes no arguments and
     35   // returns void.
     36   const FunctionProtoType *FT =
     37   BPT->getPointeeType()->getAs<FunctionProtoType>();
     38   if (!FT || !FT->getReturnType()->isVoidType() || FT->getNumParams() != 0)
     39     return false;
     40 
     41   return true;
     42 }
     43 
     44 namespace {
     45 class ASTMaker {
     46 public:
     47   ASTMaker(ASTContext &C) : C(C) {}
     48 
     49   /// Create a new BinaryOperator representing a simple assignment.
     50   BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty);
     51 
     52   /// Create a new BinaryOperator representing a comparison.
     53   BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS,
     54                                  BinaryOperator::Opcode Op);
     55 
     56   /// Create a new compound stmt using the provided statements.
     57   CompoundStmt *makeCompound(ArrayRef<Stmt*>);
     58 
     59   /// Create a new DeclRefExpr for the referenced variable.
     60   DeclRefExpr *makeDeclRefExpr(const VarDecl *D);
     61 
     62   /// Create a new UnaryOperator representing a dereference.
     63   UnaryOperator *makeDereference(const Expr *Arg, QualType Ty);
     64 
     65   /// Create an implicit cast for an integer conversion.
     66   Expr *makeIntegralCast(const Expr *Arg, QualType Ty);
     67 
     68   /// Create an implicit cast to a builtin boolean type.
     69   ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg);
     70 
     71   // Create an implicit cast for lvalue-to-rvaluate conversions.
     72   ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty);
     73 
     74   /// Create an Objective-C bool literal.
     75   ObjCBoolLiteralExpr *makeObjCBool(bool Val);
     76 
     77   /// Create an Objective-C ivar reference.
     78   ObjCIvarRefExpr *makeObjCIvarRef(const Expr *Base, const ObjCIvarDecl *IVar);
     79 
     80   /// Create a Return statement.
     81   ReturnStmt *makeReturn(const Expr *RetVal);
     82 
     83 private:
     84   ASTContext &C;
     85 };
     86 }
     87 
     88 BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
     89                                          QualType Ty) {
     90  return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
     91                                BO_Assign, Ty, VK_RValue,
     92                                OK_Ordinary, SourceLocation(), false);
     93 }
     94 
     95 BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
     96                                          BinaryOperator::Opcode Op) {
     97   assert(BinaryOperator::isLogicalOp(Op) ||
     98          BinaryOperator::isComparisonOp(Op));
     99   return new (C) BinaryOperator(const_cast<Expr*>(LHS),
    100                                 const_cast<Expr*>(RHS),
    101                                 Op,
    102                                 C.getLogicalOperationType(),
    103                                 VK_RValue,
    104                                 OK_Ordinary, SourceLocation(), false);
    105 }
    106 
    107 CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
    108   return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
    109 }
    110 
    111 DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
    112   DeclRefExpr *DR =
    113     DeclRefExpr::Create(/* Ctx = */ C,
    114                         /* QualifierLoc = */ NestedNameSpecifierLoc(),
    115                         /* TemplateKWLoc = */ SourceLocation(),
    116                         /* D = */ const_cast<VarDecl*>(D),
    117                         /* isEnclosingLocal = */ false,
    118                         /* NameLoc = */ SourceLocation(),
    119                         /* T = */ D->getType(),
    120                         /* VK = */ VK_LValue);
    121   return DR;
    122 }
    123 
    124 UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) {
    125   return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty,
    126                                VK_LValue, OK_Ordinary, SourceLocation());
    127 }
    128 
    129 ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) {
    130   return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue,
    131                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
    132 }
    133 
    134 Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) {
    135   if (Arg->getType() == Ty)
    136     return const_cast<Expr*>(Arg);
    137 
    138   return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast,
    139                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
    140 }
    141 
    142 ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) {
    143   return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean,
    144                                   const_cast<Expr*>(Arg), nullptr, VK_RValue);
    145 }
    146 
    147 ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) {
    148   QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy;
    149   return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation());
    150 }
    151 
    152 ObjCIvarRefExpr *ASTMaker::makeObjCIvarRef(const Expr *Base,
    153                                            const ObjCIvarDecl *IVar) {
    154   return new (C) ObjCIvarRefExpr(const_cast<ObjCIvarDecl*>(IVar),
    155                                  IVar->getType(), SourceLocation(),
    156                                  SourceLocation(), const_cast<Expr*>(Base),
    157                                  /*arrow=*/true, /*free=*/false);
    158 }
    159 
    160 
    161 ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) {
    162   return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal),
    163                             nullptr);
    164 }
    165 
    166 //===----------------------------------------------------------------------===//
    167 // Creation functions for faux ASTs.
    168 //===----------------------------------------------------------------------===//
    169 
    170 typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D);
    171 
    172 /// Create a fake body for dispatch_once.
    173 static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
    174   // Check if we have at least two parameters.
    175   if (D->param_size() != 2)
    176     return nullptr;
    177 
    178   // Check if the first parameter is a pointer to integer type.
    179   const ParmVarDecl *Predicate = D->getParamDecl(0);
    180   QualType PredicateQPtrTy = Predicate->getType();
    181   const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>();
    182   if (!PredicatePtrTy)
    183     return nullptr;
    184   QualType PredicateTy = PredicatePtrTy->getPointeeType();
    185   if (!PredicateTy->isIntegerType())
    186     return nullptr;
    187 
    188   // Check if the second parameter is the proper block type.
    189   const ParmVarDecl *Block = D->getParamDecl(1);
    190   QualType Ty = Block->getType();
    191   if (!isDispatchBlock(Ty))
    192     return nullptr;
    193 
    194   // Everything checks out.  Create a fakse body that checks the predicate,
    195   // sets it, and calls the block.  Basically, an AST dump of:
    196   //
    197   // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
    198   //  if (!*predicate) {
    199   //    *predicate = 1;
    200   //    block();
    201   //  }
    202   // }
    203 
    204   ASTMaker M(C);
    205 
    206   // (1) Create the call.
    207   DeclRefExpr *DR = M.makeDeclRefExpr(Block);
    208   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
    209   CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
    210                                   SourceLocation());
    211 
    212   // (2) Create the assignment to the predicate.
    213   IntegerLiteral *IL =
    214     IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1),
    215                            C.IntTy, SourceLocation());
    216   BinaryOperator *B =
    217     M.makeAssignment(
    218        M.makeDereference(
    219           M.makeLvalueToRvalue(
    220             M.makeDeclRefExpr(Predicate), PredicateQPtrTy),
    221             PredicateTy),
    222        M.makeIntegralCast(IL, PredicateTy),
    223        PredicateTy);
    224 
    225   // (3) Create the compound statement.
    226   Stmt *Stmts[2];
    227   Stmts[0] = B;
    228   Stmts[1] = CE;
    229   CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
    230 
    231   // (4) Create the 'if' condition.
    232   ImplicitCastExpr *LValToRval =
    233     M.makeLvalueToRvalue(
    234       M.makeDereference(
    235         M.makeLvalueToRvalue(
    236           M.makeDeclRefExpr(Predicate),
    237           PredicateQPtrTy),
    238         PredicateTy),
    239     PredicateTy);
    240 
    241   UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy,
    242                                            VK_RValue, OK_Ordinary,
    243                                            SourceLocation());
    244 
    245   // (5) Create the 'if' statement.
    246   IfStmt *If = new (C) IfStmt(C, SourceLocation(), nullptr, UO, CS);
    247   return If;
    248 }
    249 
    250 /// Create a fake body for dispatch_sync.
    251 static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
    252   // Check if we have at least two parameters.
    253   if (D->param_size() != 2)
    254     return nullptr;
    255 
    256   // Check if the second parameter is a block.
    257   const ParmVarDecl *PV = D->getParamDecl(1);
    258   QualType Ty = PV->getType();
    259   if (!isDispatchBlock(Ty))
    260     return nullptr;
    261 
    262   // Everything checks out.  Create a fake body that just calls the block.
    263   // This is basically just an AST dump of:
    264   //
    265   // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) {
    266   //   block();
    267   // }
    268   //
    269   ASTMaker M(C);
    270   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
    271   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
    272   CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue,
    273                                   SourceLocation());
    274   return CE;
    275 }
    276 
    277 static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
    278 {
    279   // There are exactly 3 arguments.
    280   if (D->param_size() != 3)
    281     return nullptr;
    282 
    283   // Signature:
    284   // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
    285   //                                 void *__newValue,
    286   //                                 void * volatile *__theValue)
    287   // Generate body:
    288   //   if (oldValue == *theValue) {
    289   //    *theValue = newValue;
    290   //    return YES;
    291   //   }
    292   //   else return NO;
    293 
    294   QualType ResultTy = D->getReturnType();
    295   bool isBoolean = ResultTy->isBooleanType();
    296   if (!isBoolean && !ResultTy->isIntegralType(C))
    297     return nullptr;
    298 
    299   const ParmVarDecl *OldValue = D->getParamDecl(0);
    300   QualType OldValueTy = OldValue->getType();
    301 
    302   const ParmVarDecl *NewValue = D->getParamDecl(1);
    303   QualType NewValueTy = NewValue->getType();
    304 
    305   assert(OldValueTy == NewValueTy);
    306 
    307   const ParmVarDecl *TheValue = D->getParamDecl(2);
    308   QualType TheValueTy = TheValue->getType();
    309   const PointerType *PT = TheValueTy->getAs<PointerType>();
    310   if (!PT)
    311     return nullptr;
    312   QualType PointeeTy = PT->getPointeeType();
    313 
    314   ASTMaker M(C);
    315   // Construct the comparison.
    316   Expr *Comparison =
    317     M.makeComparison(
    318       M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy),
    319       M.makeLvalueToRvalue(
    320         M.makeDereference(
    321           M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
    322           PointeeTy),
    323         PointeeTy),
    324       BO_EQ);
    325 
    326   // Construct the body of the IfStmt.
    327   Stmt *Stmts[2];
    328   Stmts[0] =
    329     M.makeAssignment(
    330       M.makeDereference(
    331         M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy),
    332         PointeeTy),
    333       M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy),
    334       NewValueTy);
    335 
    336   Expr *BoolVal = M.makeObjCBool(true);
    337   Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
    338                            : M.makeIntegralCast(BoolVal, ResultTy);
    339   Stmts[1] = M.makeReturn(RetVal);
    340   CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2));
    341 
    342   // Construct the else clause.
    343   BoolVal = M.makeObjCBool(false);
    344   RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal)
    345                      : M.makeIntegralCast(BoolVal, ResultTy);
    346   Stmt *Else = M.makeReturn(RetVal);
    347 
    348   /// Construct the If.
    349   Stmt *If =
    350     new (C) IfStmt(C, SourceLocation(), nullptr, Comparison, Body,
    351                    SourceLocation(), Else);
    352 
    353   return If;
    354 }
    355 
    356 Stmt *BodyFarm::getBody(const FunctionDecl *D) {
    357   D = D->getCanonicalDecl();
    358 
    359   Optional<Stmt *> &Val = Bodies[D];
    360   if (Val.hasValue())
    361     return Val.getValue();
    362 
    363   Val = nullptr;
    364 
    365   if (D->getIdentifier() == nullptr)
    366     return nullptr;
    367 
    368   StringRef Name = D->getName();
    369   if (Name.empty())
    370     return nullptr;
    371 
    372   FunctionFarmer FF;
    373 
    374   if (Name.startswith("OSAtomicCompareAndSwap") ||
    375       Name.startswith("objc_atomicCompareAndSwap")) {
    376     FF = create_OSAtomicCompareAndSwap;
    377   }
    378   else {
    379     FF = llvm::StringSwitch<FunctionFarmer>(Name)
    380           .Case("dispatch_sync", create_dispatch_sync)
    381           .Case("dispatch_once", create_dispatch_once)
    382           .Default(nullptr);
    383   }
    384 
    385   if (FF) { Val = FF(C, D); }
    386   return Val.getValue();
    387 }
    388 
    389 static Stmt *createObjCPropertyGetter(ASTContext &Ctx,
    390                                       const ObjCPropertyDecl *Prop) {
    391   // First, find the backing ivar.
    392   const ObjCIvarDecl *IVar = Prop->getPropertyIvarDecl();
    393   if (!IVar)
    394     return nullptr;
    395 
    396   // Ignore weak variables, which have special behavior.
    397   if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
    398     return nullptr;
    399 
    400   // Look to see if Sema has synthesized a body for us. This happens in
    401   // Objective-C++ because the return value may be a C++ class type with a
    402   // non-trivial copy constructor. We can only do this if we can find the
    403   // @synthesize for this property, though (or if we know it's been auto-
    404   // synthesized).
    405   const ObjCImplementationDecl *ImplDecl =
    406     IVar->getContainingInterface()->getImplementation();
    407   if (ImplDecl) {
    408     for (const auto *I : ImplDecl->property_impls()) {
    409       if (I->getPropertyDecl() != Prop)
    410         continue;
    411 
    412       if (I->getGetterCXXConstructor()) {
    413         ASTMaker M(Ctx);
    414         return M.makeReturn(I->getGetterCXXConstructor());
    415       }
    416     }
    417   }
    418 
    419   // Sanity check that the property is the same type as the ivar, or a
    420   // reference to it, and that it is either an object pointer or trivially
    421   // copyable.
    422   if (!Ctx.hasSameUnqualifiedType(IVar->getType(),
    423                                   Prop->getType().getNonReferenceType()))
    424     return nullptr;
    425   if (!IVar->getType()->isObjCLifetimeType() &&
    426       !IVar->getType().isTriviallyCopyableType(Ctx))
    427     return nullptr;
    428 
    429   // Generate our body:
    430   //   return self->_ivar;
    431   ASTMaker M(Ctx);
    432 
    433   const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl();
    434 
    435   Expr *loadedIVar =
    436     M.makeObjCIvarRef(
    437       M.makeLvalueToRvalue(
    438         M.makeDeclRefExpr(selfVar),
    439         selfVar->getType()),
    440       IVar);
    441 
    442   if (!Prop->getType()->isReferenceType())
    443     loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType());
    444 
    445   return M.makeReturn(loadedIVar);
    446 }
    447 
    448 Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
    449   // We currently only know how to synthesize property accessors.
    450   if (!D->isPropertyAccessor())
    451     return nullptr;
    452 
    453   D = D->getCanonicalDecl();
    454 
    455   Optional<Stmt *> &Val = Bodies[D];
    456   if (Val.hasValue())
    457     return Val.getValue();
    458   Val = nullptr;
    459 
    460   const ObjCPropertyDecl *Prop = D->findPropertyDecl();
    461   if (!Prop)
    462     return nullptr;
    463 
    464   // For now, we only synthesize getters.
    465   if (D->param_size() != 0)
    466     return nullptr;
    467 
    468   Val = createObjCPropertyGetter(C, Prop);
    469 
    470   return Val.getValue();
    471 }
    472 
    473