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