Exemplo n.º 1
0
void clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, 
                            BugReporter& BR) {
  FindEscaped FS(&cfg);
  FS.getCFG().VisitBlockStmts(FS);
  DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
  L.runOnAllBlocks(cfg, &A);
}
Exemplo n.º 2
0
// OutputPossibleOverflows - We've found a possible overflow earlier,
// now check whether Body might contain a comparison which might be
// preventing the overflow.
// This doesn't do flow analysis, range analysis, or points-to analysis; it's
// just a dumb "is there a comparison" scan.  The aim here is to
// detect the most blatent cases of overflow and educate the
// programmer.
void MallocOverflowSecurityChecker::OutputPossibleOverflows(
  llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
  const Decl *D, BugReporter &BR, AnalysisManager &mgr) const {
  // By far the most common case: nothing to check.
  if (PossibleMallocOverflows.empty())
    return;

  // Delete any possible overflows which have a comparison.
  CheckOverflowOps c(PossibleMallocOverflows, BR.getContext());
  c.Visit(mgr.getAnalysisContext(D)->getBody());

  // Output warnings for all overflows that are left.
  for (CheckOverflowOps::theVecType::iterator
       i = PossibleMallocOverflows.begin(),
       e = PossibleMallocOverflows.end();
       i != e;
       ++i) {
    SourceRange R = i->mulop->getSourceRange();
    BR.EmitBasicReport("MallocOverflowSecurityChecker",
      "the computation of the size of the memory allocation may overflow",
      PathDiagnosticLocation::createOperatorLoc(i->mulop,
                                                BR.getSourceManager()),
      &R, 1);
  }
}
Exemplo n.º 3
0
void NSErrorChecker::FlushReports(BugReporter& BR) {
  // Get the analysis engine and the exploded analysis graph.
  ExplodedGraph& G = Eng.getGraph();

  // Get the ASTContext, which is useful for querying type information.
  ASTContext &Ctx = BR.getContext();

  QualType ResultTy;
  llvm::SmallVector<VarDecl*, 5> ErrorParams;

  if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
    CheckSignature(*MD, ResultTy, ErrorParams);
  else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
    CheckSignature(*FD, ResultTy, ErrorParams);
  else
    return;

  if (ErrorParams.empty())
    return;

  if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl);

  for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end();
       RI!=RE; ++RI) {
    // Scan the parameters for an implicit null dereference.
    for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(),
          E=ErrorParams.end(); I!=E; ++I)
        CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR);
  }
}
void iOSAppSecAbusingURLSchemesChecker::checkASTDecl(const ObjCImplementationDecl *pImplDecl, AnalysisManager &rMgr, BugReporter &rBR) const 
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER" ) ;

  ASTContext &Ctx = rBR.getContext() ;  

  do
  {
    initIdentifierInfo( Ctx ) ;

    const ObjCInterfaceDecl *pIfDecl = CMSecCommon::isSupportedProtocol( pImplDecl ->getClassInterface(), m_piiUIApplicationDelegate ) ;

    if ( !pIfDecl )
    { 
      MSEC_DEBUG( "redwud: ", "!pIfDecl" ) ;
      break ;
    }

    //Pitfall: This should be instance method
    for ( ObjCImplementationDecl::instmeth_iterator pItem = pImplDecl ->instmeth_begin()
            , pEndItem = pImplDecl ->instmeth_end(); 
          pItem != pEndItem;
          ++pItem )
    {
      checkASTDecl( (*pItem), rMgr, rBR ) ; 
    } 
  } while (_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT" ) ;
}
void iOSAppSecLeakingWebCachesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // connection:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiConnection)
    {
      //MSEC_DEBUG("redwud: ","!connection: " << S.getAsString() ) ;
      break ;
    }

    ASTContext &Ctx = rBR.getContext() ; 

    // Two arguments
    if ( S.getNumArgs() != 2 )
    {
      break ;
    }
    
    // willCacheResponse:
    if ( S.getIdentifierInfoForSlot(1) != m_piiWillCacheResponse )
    {
      break ;
    }

    //Note: Intentionally made it common for both
    if ( !checkWillCacheResponse( pMD, Ctx ) )
    {
      break ;
    } 
    
    CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
      , m_szReportDesc, rBR, pMD ) ; 
      
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) {

    ObjCInterfaceDecl* ID = D->getClassInterface();
    IvarUsageMap M;


    ASTContext &Ctx = BR.getContext();

    // Iterate over the ivars.
    for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
            I!=E; ++I) {

        ObjCIvarDecl* ID = *I;

        // Ignore ivars that aren't private.
        if (ID->getAccessControl() != ObjCIvarDecl::Private)
            continue;

        // Skip IB Outlets.
        if (ID->getAttr<IBOutletAttr>())
            continue;

        M[ID] = Unused;
    }

    if (M.empty())
        return;

    // Now scan the methods for accesses.
    for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx),
            E = D->instmeth_end(Ctx); I!=E; ++I)
        Scan(M, (*I)->getBody(Ctx));

    // Scan for @synthesized property methods that act as setters/getters
    // to an ivar.
    for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx),
            E = D->propimpl_end(Ctx); I!=E; ++I)
        Scan(M, *I);

    // Find ivars that are unused.
    for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
        if (I->second == Unused) {

            std::ostringstream os;
            os << "Instance variable '" << I->first->getNameAsString()
               << "' in class '" << ID->getNameAsString()
               << "' is never used by the methods in its @implementation "
               "(although it may be used by category methods).";

            BR.EmitBasicReport("Unused instance variable", "Optimization",
                               os.str().c_str(), I->first->getLocation());
        }
}
void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
                                        AnalysisManager &Mgr,
                                        BugReporter &BR) const {
  ASTContext &Ctx = BR.getContext();

  // We need to initialize the selector table once.
  if (!IsInitialized)
    initializeSelectors(Ctx);

  // Find out whether this class has a superclass that we are supposed to check.
  StringRef SuperclassName;
  if (!isCheckableClass(D, SuperclassName))
    return;


  // Iterate over all instance methods.
  for (auto *MD : D->instance_methods()) {
    Selector S = MD->getSelector();
    // Find out whether this is a selector that we want to check.
    if (!SelectorsForClass[SuperclassName].count(S))
      continue;

    // Check if the method calls its superclass implementation.
    if (MD->getBody())
    {
      FindSuperCallVisitor Visitor(S);
      Visitor.TraverseDecl(MD);

      // It doesn't call super, emit a diagnostic.
      if (!Visitor.DoesCallSuper) {
        PathDiagnosticLocation DLoc =
          PathDiagnosticLocation::createEnd(MD->getBody(),
                                            BR.getSourceManager(),
                                            Mgr.getAnalysisDeclContext(D));

        const char *Name = "Missing call to superclass";
        SmallString<320> Buf;
        llvm::raw_svector_ostream os(Buf);

        os << "The '" << S.getAsString()
           << "' instance method in " << SuperclassName.str() << " subclass '"
           << *D << "' is missing a [super " << S.getAsString() << "] call";

        BR.EmitBasicReport(MD, this, Name, categories::CoreFoundationObjectiveC,
                           os.str(), DLoc);
      }
    }
  }
}
Exemplo n.º 8
0
void ento::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
                                    BugReporter& BR) {

  const ObjCInterfaceDecl* D = ID->getClassInterface();
  const ObjCInterfaceDecl* C = D->getSuperClass();

  if (!C)
    return;

  ASTContext& Ctx = BR.getContext();

  // Build a DenseMap of the methods for quick querying.
  typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
  MapTy IMeths;
  unsigned NumMethods = 0;

  for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
       E=ID->instmeth_end(); I!=E; ++I) {

    ObjCMethodDecl* M = *I;
    IMeths[M->getSelector()] = M;
    ++NumMethods;
  }

  // Now recurse the class hierarchy chain looking for methods with the
  // same signatures.
  while (C && NumMethods) {
    for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
         E=C->instmeth_end(); I!=E; ++I) {

      ObjCMethodDecl* M = *I;
      Selector S = M->getSelector();

      MapTy::iterator MI = IMeths.find(S);

      if (MI == IMeths.end() || MI->second == 0)
        continue;

      --NumMethods;
      ObjCMethodDecl* MethDerived = MI->second;
      MI->second = 0;

      CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
    }

    C = C->getSuperClass();
  }
}
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
                                              BugReporter &B,
                                              ExprEngine &Eng) const {
  CFGBlocksSet reachable, visited;

  if (Eng.hasWorkRemaining())
    return;

  CFG *C = 0;
  ParentMap *PM = 0;
  // Iterate over ExplodedGraph
  for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
      I != E; ++I) {
    const ProgramPoint &P = I->getLocation();
    const LocationContext *LC = P.getLocationContext();

    // Save the CFG if we don't have it already
    if (!C)
      C = LC->getAnalysisContext()->getUnoptimizedCFG();
    if (!PM)
      PM = &LC->getParentMap();

    if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
      const CFGBlock *CB = BE->getBlock();
      reachable.insert(CB->getBlockID());
    }
  }

  // Bail out if we didn't get the CFG or the ParentMap.
  if (!C || !PM)
    return;

  ASTContext &Ctx = B.getContext();

  // Find CFGBlocks that were not covered by any node
  for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
    const CFGBlock *CB = *I;
    // Check if the block is unreachable
    if (reachable.count(CB->getBlockID()))
      continue;

    // Check if the block is empty (an artificial block)
    if (isEmptyCFGBlock(CB))
      continue;

    // Find the entry points for this block
    if (!visited.count(CB->getBlockID()))
      FindUnreachableEntryPoints(CB, reachable, visited);

    // This block may have been pruned; check if we still want to report it
    if (reachable.count(CB->getBlockID()))
      continue;

    // Check for false positives
    if (CB->size() > 0 && isInvalidPath(CB, *PM))
      continue;

    // Special case for __builtin_unreachable.
    // FIXME: This should be extended to include other unreachable markers,
    // such as llvm_unreachable.
    if (!CB->empty()) {
      CFGElement First = CB->front();
      if (const CFGStmt *S = First.getAs<CFGStmt>()) {
        if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
          if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
            continue;
        }
      }
    }

    // We found a block that wasn't covered - find the statement to report
    SourceRange SR;
    SourceLocation SL;
    if (const Stmt *S = getUnreachableStmt(CB)) {
      SR = S->getSourceRange();
      SL = S->getLocStart();
      if (SR.isInvalid() || SL.isInvalid())
        continue;
    }
    else
      continue;

    // Check if the SourceLocation is in a system header
    const SourceManager &SM = B.getSourceManager();
    if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
      continue;

    B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
        " executed", SL, SR);
  }
}
Exemplo n.º 10
0
static void checkObjCDealloc(const ObjCImplementationDecl *D,
                             const LangOptions& LOpts, BugReporter& BR) {

  assert (LOpts.getGC() != LangOptions::GCOnly);

  ASTContext &Ctx = BR.getContext();
  const ObjCInterfaceDecl *ID = D->getClassInterface();

  // Does the class contain any ivars that are pointers (or id<...>)?
  // If not, skip the check entirely.
  // NOTE: This is motivated by PR 2517:
  //        http://llvm.org/bugs/show_bug.cgi?id=2517

  bool containsPointerIvar = false;

  for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
       I!=E; ++I) {

    ObjCIvarDecl *ID = *I;
    QualType T = ID->getType();

    if (!T->isObjCObjectPointerType() ||
        ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
        ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
      continue;

    containsPointerIvar = true;
    break;
  }

  if (!containsPointerIvar)
    return;

  // Determine if the class subclasses NSObject.
  IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
  IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");


  for ( ; ID ; ID = ID->getSuperClass()) {
    IdentifierInfo *II = ID->getIdentifier();

    if (II == NSObjectII)
      break;

    // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
    // need to implement -dealloc.  They implement tear down in another way,
    // which we should try and catch later.
    //  http://llvm.org/bugs/show_bug.cgi?id=3187
    if (II == SenTestCaseII)
      return;
  }

  if (!ID)
    return;

  // Get the "dealloc" selector.
  IdentifierInfo* II = &Ctx.Idents.get("dealloc");
  Selector S = Ctx.Selectors.getSelector(0, &II);
  ObjCMethodDecl *MD = 0;

  // Scan the instance methods for "dealloc".
  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
       E = D->instmeth_end(); I!=E; ++I) {

    if ((*I)->getSelector() == S) {
      MD = *I;
      break;
    }
  }

  PathDiagnosticLocation DLoc =
    PathDiagnosticLocation::createBegin(D, BR.getSourceManager());

  if (!MD) { // No dealloc found.

    const char* name = LOpts.getGC() == LangOptions::NonGC
                       ? "missing -dealloc"
                       : "missing -dealloc (Hybrid MM, non-GC)";

    std::string buf;
    llvm::raw_string_ostream os(buf);
    os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";

    BR.EmitBasicReport(D, name, categories::CoreFoundationObjectiveC,
                       os.str(), DLoc);
    return;
  }

  // dealloc found.  Scan for missing [super dealloc].
  if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {

    const char* name = LOpts.getGC() == LangOptions::NonGC
                       ? "missing [super dealloc]"
                       : "missing [super dealloc] (Hybrid MM, non-GC)";

    std::string buf;
    llvm::raw_string_ostream os(buf);
    os << "The 'dealloc' instance method in Objective-C class '" << *D
       << "' does not send a 'dealloc' message to its super class"
           " (missing [super dealloc])";

    BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
                       os.str(), DLoc);
    return;
  }

  // Get the "release" selector.
  IdentifierInfo* RII = &Ctx.Idents.get("release");
  Selector RS = Ctx.Selectors.getSelector(0, &RII);

  // Get the "self" identifier
  IdentifierInfo* SelfII = &Ctx.Idents.get("self");

  // Scan for missing and extra releases of ivars used by implementations
  // of synthesized properties
  for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
       E = D->propimpl_end(); I!=E; ++I) {

    // We can only check the synthesized properties
    if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
      continue;

    ObjCIvarDecl *ID = I->getPropertyIvarDecl();
    if (!ID)
      continue;

    QualType T = ID->getType();
    if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
      continue;

    const ObjCPropertyDecl *PD = I->getPropertyDecl();
    if (!PD)
      continue;

    // ivars cannot be set via read-only properties, so we'll skip them
    if (PD->isReadOnly())
      continue;

    // ivar must be released if and only if the kind of setter was not 'assign'
    bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
    if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
       != requiresRelease) {
      const char *name = 0;
      std::string buf;
      llvm::raw_string_ostream os(buf);

      if (requiresRelease) {
        name = LOpts.getGC() == LangOptions::NonGC
               ? "missing ivar release (leak)"
               : "missing ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID
           << "' instance variable was retained by a synthesized property but "
              "wasn't released in 'dealloc'";
      } else {
        name = LOpts.getGC() == LangOptions::NonGC
               ? "extra ivar release (use-after-release)"
               : "extra ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID
           << "' instance variable was not retained by a synthesized property "
              "but was released in 'dealloc'";
      }

      PathDiagnosticLocation SDLoc =
        PathDiagnosticLocation::createBegin(*I, BR.getSourceManager());

      BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
                         os.str(), SDLoc);
    }
  }
}
Exemplo n.º 11
0
void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
                                        AnalysisManager &Mgr,
                                        BugReporter &BR) const {
  ASTContext &Ctx = BR.getContext();

  if (!isUIViewControllerSubclass(Ctx, D))
    return;

  const char *SelectorNames[] = 
    {"addChildViewController", "viewDidAppear", "viewDidDisappear", 
     "viewWillAppear", "viewWillDisappear", "removeFromParentViewController",
     "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload",
     "viewDidLoad"};
  const unsigned SelectorArgumentCounts[] =
   {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
  const size_t SelectorCount = llvm::array_lengthof(SelectorNames);
  assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount);

  // Fill the Selectors SmallSet with all selectors we want to check.
  llvm::SmallSet<Selector, 16> Selectors;
  for (size_t i = 0; i < SelectorCount; i++) { 
    unsigned ArgumentCount = SelectorArgumentCounts[i];
    const char *SelectorCString = SelectorNames[i];

    // Get the selector.
    IdentifierInfo *II = &Ctx.Idents.get(SelectorCString);
    Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II));
  }

  // Iterate over all instance methods.
  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
                                                 E = D->instmeth_end();
       I != E; ++I) {
    Selector S = (*I)->getSelector();
    // Find out whether this is a selector that we want to check.
    if (!Selectors.count(S))
      continue;

    ObjCMethodDecl *MD = *I;

    // Check if the method calls its superclass implementation.
    if (MD->getBody())
    {
      FindSuperCallVisitor Visitor(S);
      Visitor.TraverseDecl(MD);

      // It doesn't call super, emit a diagnostic.
      if (!Visitor.DoesCallSuper) {
        PathDiagnosticLocation DLoc =
          PathDiagnosticLocation::createEnd(MD->getBody(),
                                            BR.getSourceManager(),
                                            Mgr.getAnalysisDeclContext(D));

        const char *Name = "Missing call to superclass";
        SmallString<256> Buf;
        llvm::raw_svector_ostream os(Buf);

        os << "The '" << S.getAsString() 
           << "' instance method in UIViewController subclass '" << *D
           << "' is missing a [super " << S.getAsString() << "] call";

        BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
                           os.str(), DLoc);
      }
    }
  }
}
Exemplo n.º 12
0
void CloneChecker::reportSuspiciousClones(
    BugReporter &BR, AnalysisManager &Mgr,
    std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
  std::vector<VariablePattern::SuspiciousClonePair> Pairs;

  for (const CloneDetector::CloneGroup &Group : CloneGroups) {
    for (unsigned i = 0; i < Group.size(); ++i) {
      VariablePattern PatternA(Group[i]);

      for (unsigned j = i + 1; j < Group.size(); ++j) {
        VariablePattern PatternB(Group[j]);

        VariablePattern::SuspiciousClonePair ClonePair;
        // For now, we only report clones which break the variable pattern just
        // once because multiple differences in a pattern are an indicator that
        // those differences are maybe intended (e.g. because it's actually a
        // different algorithm).
        // FIXME: In very big clones even multiple variables can be unintended,
        // so replacing this number with a percentage could better handle such
        // cases. On the other hand it could increase the false-positive rate
        // for all clones if the percentage is too high.
        if (PatternA.countPatternDifferences(PatternB, &ClonePair) == 1) {
          Pairs.push_back(ClonePair);
          break;
        }
      }
    }
  }

  if (!BT_Suspicious)
    BT_Suspicious.reset(
        new BugType(this, "Suspicious code clone", "Code clone"));

  ASTContext &ACtx = BR.getContext();
  SourceManager &SM = ACtx.getSourceManager();
  AnalysisDeclContext *ADC =
      Mgr.getAnalysisDeclContext(ACtx.getTranslationUnitDecl());

  for (VariablePattern::SuspiciousClonePair &Pair : Pairs) {
    // FIXME: We are ignoring the suggestions currently, because they are
    // only 50% accurate (even if the second suggestion is unavailable),
    // which may confuse the user.
    // Think how to perform more accurate suggestions?

    auto R = llvm::make_unique<BugReport>(
        *BT_Suspicious,
        "Potential copy-paste error; did you really mean to use '" +
            Pair.FirstCloneInfo.Variable->getNameAsString() + "' here?",
        PathDiagnosticLocation::createBegin(Pair.FirstCloneInfo.Mention, SM,
                                            ADC));
    R->addRange(Pair.FirstCloneInfo.Mention->getSourceRange());

    R->addNote("Similar code using '" +
                   Pair.SecondCloneInfo.Variable->getNameAsString() + "' here",
               PathDiagnosticLocation::createBegin(Pair.SecondCloneInfo.Mention,
                                                   SM, ADC),
               Pair.SecondCloneInfo.Mention->getSourceRange());

    BR.emitReport(std::move(R));
  }
}
void iOSAppSecAbusingURLSchemesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // application:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiApplication )
    {
      //MSEC_DEBUG("redwud: ","!application: " << S.getAsString() ) ;
      break ;
    }

    unsigned iArgs = S.getNumArgs() ;
    ASTContext &Ctx = rBR.getContext() ; 

    //
    //openURL:
    //

    do
    {
      if ( iArgs != 4 )
      {
        break ;
      }
      
      if ( (S.getIdentifierInfoForSlot(1) != m_piiOpenURL) 
           || (S.getIdentifierInfoForSlot(2) != m_piiSourceApplication)
           || (S.getIdentifierInfoForSlot(3) != m_piiAnnotation ) )
      {
        break ;
      }
          
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc 
        , rBR, pMD ) ; 
    
    } while(_PASSING_) ;

    //
    //handleOpenURL:
    //

    do
    {
      if ( iArgs != 2 )
      {
        break ;
      }
      
      if ( S.getIdentifierInfoForSlot(1) != m_piiHandleOpenURL )
      {
        break ;
      }
      
      //Note: Intentionally made it common for both
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc, rBR, pMD ) ;
    
    } while(_PASSING_) ; //handleOpenURL:
  
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
Exemplo n.º 14
0
static void checkObjCDealloc(const CheckerBase *Checker,
                             const ObjCImplementationDecl *D,
                             const LangOptions &LOpts, BugReporter &BR) {

  assert(LOpts.getGC() != LangOptions::GCOnly);
  assert(!LOpts.ObjCAutoRefCount);

  ASTContext &Ctx = BR.getContext();
  const ObjCInterfaceDecl *ID = D->getClassInterface();

  // Does the class contain any synthesized properties that are retainable?
  // If not, skip the check entirely.
  bool containsRetainedSynthesizedProperty = false;
  for (const auto *I : D->property_impls()) {
    const ObjCIvarDecl *ID = nullptr;
    const ObjCPropertyDecl *PD = nullptr;
    if (!isSynthesizedRetainableProperty(I, &ID, &PD))
      continue;

    if (synthesizedPropertyRequiresRelease(PD)) {
      containsRetainedSynthesizedProperty = true;
      break;
    }
  }

  if (!containsRetainedSynthesizedProperty)
    return;

  // Determine if the class subclasses NSObject.
  IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
  IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");

  for ( ; ID ; ID = ID->getSuperClass()) {
    IdentifierInfo *II = ID->getIdentifier();

    if (II == NSObjectII)
      break;

    // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
    // need to implement -dealloc.  They implement tear down in another way,
    // which we should try and catch later.
    //  http://llvm.org/bugs/show_bug.cgi?id=3187
    if (II == SenTestCaseII)
      return;
  }

  if (!ID)
    return;

  // Get the "dealloc" selector.
  IdentifierInfo* II = &Ctx.Idents.get("dealloc");
  Selector S = Ctx.Selectors.getSelector(0, &II);
  const ObjCMethodDecl *MD = nullptr;

  // Scan the instance methods for "dealloc".
  for (const auto *I : D->instance_methods()) {
    if (I->getSelector() == S) {
      MD = I;
      break;
    }
  }

  if (!MD) { // No dealloc found.

    const char* name = LOpts.getGC() == LangOptions::NonGC
                       ? "missing -dealloc"
                       : "missing -dealloc (Hybrid MM, non-GC)";

    std::string buf;
    llvm::raw_string_ostream os(buf);
    os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";

    PathDiagnosticLocation DLoc =
        PathDiagnosticLocation::createBegin(D, BR.getSourceManager());

    BR.EmitBasicReport(D, Checker, name, categories::CoreFoundationObjectiveC,
                       os.str(), DLoc);
    return;
  }

  // Get the "release" selector.
  IdentifierInfo* RII = &Ctx.Idents.get("release");
  Selector RS = Ctx.Selectors.getSelector(0, &RII);

  // Get the "self" identifier
  IdentifierInfo* SelfII = &Ctx.Idents.get("self");

  // Scan for missing and extra releases of ivars used by implementations
  // of synthesized properties
  for (const auto *I : D->property_impls()) {
    const ObjCIvarDecl *ID = nullptr;
    const ObjCPropertyDecl *PD = nullptr;
    if (!isSynthesizedRetainableProperty(I, &ID, &PD))
      continue;

    bool requiresRelease = synthesizedPropertyRequiresRelease(PD);
    if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
       != requiresRelease) {
      const char *name = nullptr;
      std::string buf;
      llvm::raw_string_ostream os(buf);

      if (requiresRelease) {
        name = LOpts.getGC() == LangOptions::NonGC
               ? "missing ivar release (leak)"
               : "missing ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID << "' instance variable in '" << *D
           << "' was retained by a synthesized property "
              "but was not released in 'dealloc'";
      } else {
        // It is common for the ivars for read-only assign properties to
        // always be stored retained, so don't warn for a release in
        // dealloc for the ivar backing these properties.
        if (PD->isReadOnly())
          continue;

        name = LOpts.getGC() == LangOptions::NonGC
               ? "extra ivar release (use-after-release)"
               : "extra ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID << "' instance variable in '" << *D
           << "' was not retained by a synthesized property "
              "but was released in 'dealloc'";
      }

      // If @synthesize statement is missing, fall back to @property statement.
      const Decl *SPDecl = I->getLocation().isValid()
                               ? static_cast<const Decl *>(I)
                               : static_cast<const Decl *>(PD);
      PathDiagnosticLocation SPLoc =
          PathDiagnosticLocation::createBegin(SPDecl, BR.getSourceManager());

      BR.EmitBasicReport(MD, Checker, name,
                         categories::CoreFoundationObjectiveC, os.str(), SPLoc);
    }
  }
}