Exemplo n.º 1
0
  void FunctionChecker::checkASTDecl(const FunctionDecl *FD, AnalysisManager &mgr, BugReporter &BR) const {
    if (FD->hasAttr<CMSThreadSafeAttr>())
      return;
    if (FD->isInExternCContext()) {
      std::string buf;
      std::string dname = FD->getQualifiedNameAsString();
      if (dname.compare(dname.size() - 1, 1, "_") == 0) {
        llvm::raw_string_ostream os(buf);
        os << "function '" << dname
           << "' is in an extern \"C\" context and most likely accesses or modifies fortran variables in a "
              "'COMMONBLOCK'.\n";
        clang::ento::PathDiagnosticLocation::createBegin(FD, BR.getSourceManager());
        //		BR.EmitBasicReport(FD, "COMMONBLOCK variable accessed or modified","ThreadSafety",os.str(), FDLoc);
        std::string ostring = "function '" + dname + "' static variable 'COMMONBLOCK'.\n";
        std::string tname = "function-checker.txt.unsorted";
        support::writeLog(ostring, tname);
      }
    }

    const char *sfile = BR.getSourceManager().getPresumedLoc(FD->getLocation()).getFilename();
    if (!support::isCmsLocalFile(sfile))
      return;
    std::string fname(sfile);
    if (!support::isInterestingLocation(fname))
      return;
    if (FD->doesThisDeclarationHaveABody()) {
      FWalker walker(this, BR, mgr.getAnalysisDeclContext(FD));
      walker.Visit(FD->getBody());
    }
  }
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
/// An AST check that diagnose when the class requires a -dealloc method and
/// is missing one.
void ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D,
                                      AnalysisManager &Mgr,
                                      BugReporter &BR) const {
  assert(Mgr.getLangOpts().getGC() != LangOptions::GCOnly);
  assert(!Mgr.getLangOpts().ObjCAutoRefCount);
  initIdentifierInfoAndSelectors(Mgr.getASTContext());

  const ObjCInterfaceDecl *ID = D->getClassInterface();
  // If the class is known to have a lifecycle with a separate teardown method
  // then it may not require a -dealloc method.
  if (classHasSeparateTeardown(ID))
    return;

  // Does the class contain any synthesized properties that are retainable?
  // If not, skip the check entirely.
  const ObjCPropertyImplDecl *PropImplRequiringRelease = nullptr;
  bool HasOthers = false;
  for (const auto *I : D->property_impls()) {
    if (getDeallocReleaseRequirement(I) == ReleaseRequirement::MustRelease) {
      if (!PropImplRequiringRelease)
        PropImplRequiringRelease = I;
      else {
        HasOthers = true;
        break;
      }
    }
  }

  if (!PropImplRequiringRelease)
    return;

  const ObjCMethodDecl *MD = nullptr;

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

  if (!MD) { // No dealloc found.
    const char* Name = "Missing -dealloc";

    std::string Buf;
    llvm::raw_string_ostream OS(Buf);
    OS << "'" << *D << "' lacks a 'dealloc' instance method but "
       << "must release '" << *PropImplRequiringRelease->getPropertyIvarDecl()
       << "'";

    if (HasOthers)
      OS << " and others";
    PathDiagnosticLocation DLoc =
        PathDiagnosticLocation::createBegin(D, BR.getSourceManager());

    BR.EmitBasicReport(D, this, Name, categories::CoreFoundationObjectiveC,
                       OS.str(), DLoc);
    return;
  }
}
Exemplo n.º 4
0
void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->isThisDeclarationADefinition())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("NSError"); 

  bool hasNSError = false;
  for (const auto *I : D->params())  {
    if (IsNSError(I->getType(), II)) {
      hasNSError = true;
      break;
    }
  }

  if (hasNSError) {
    const char *err = "Method accepting NSError** "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing NSError**",
                       "Coding conventions (Apple)", err, L);
  }
}
Exemplo n.º 5
0
void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
                                        AnalysisManager &mgr,
                                        BugReporter &BR) const {
  if (!D->doesThisDeclarationHaveABody())
    return;
  if (!D->getReturnType()->isVoidType())
    return;

  if (!II)
    II = &D->getASTContext().Idents.get("CFErrorRef"); 

  bool hasCFError = false;
  for (auto I : D->params())  {
    if (IsCFError(I->getType(), II)) {
      hasCFError = true;
      break;
    }
  }

  if (hasCFError) {
    const char *err = "Function accepting CFErrorRef* "
        "should have a non-void return value to indicate whether or not an "
        "error occurred";
    PathDiagnosticLocation L =
      PathDiagnosticLocation::create(D, BR.getSourceManager());
    BR.EmitBasicReport(D, this, "Bad return type when passing CFErrorRef*",
                       "Coding conventions (Apple)", err, L);
  }
}
Exemplo n.º 6
0
void ThrUnsafeFCallChecker::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager& mgr,
                    BugReporter &BR) const {
       	const SourceManager &SM = BR.getSourceManager();
       	PathDiagnosticLocation DLoc =PathDiagnosticLocation::createBegin( MD, SM );
	if ( SM.isInSystemHeader(DLoc.asLocation()) || SM.isInExternCSystemHeader(DLoc.asLocation()) ) return;
       	if (!MD->doesThisDeclarationHaveABody()) return;
	clangcms::TUFWalker walker(this,BR, mgr.getAnalysisDeclContext(MD));
	walker.Visit(MD->getBody());
       	return;
} 
Exemplo n.º 7
0
void FunctionChecker::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager& mgr,
                    BugReporter &BR) const {
	if ( MD->hasAttr<CMSThreadSafeAttr>()) return;
 	const char *sfile=BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
 	if (!support::isCmsLocalFile(sfile)) return;
	std::string fname(sfile);
	if ( fname.find("/test/") != std::string::npos) return;
      	if (!MD->doesThisDeclarationHaveABody()) return;
	FWalker walker(BR, mgr.getAnalysisDeclContext(MD));
	walker.Visit(MD->getBody());
       	return;
} 
Exemplo n.º 8
0
  void getByChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
    const clang::SourceManager &SM = BR.getSourceManager();
    clang::ento::PathDiagnosticLocation DLoc = clang::ento::PathDiagnosticLocation::createBegin(TD, SM);
    if (SM.isInSystemHeader(DLoc.asLocation()) || SM.isInExternCSystemHeader(DLoc.asLocation()))
      return;

    for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
      if (I->doesThisDeclarationHaveABody()) {
        clangcms::Walker walker(this, BR, mgr.getAnalysisDeclContext(*I));
        walker.Visit(I->getBody());
      }
    }
    return;
  }
  void DanglingDelegateChecker::checkASTDecl(const ObjCImplDecl *implDecl, AnalysisManager& manager, BugReporter &bugReporter) const {

    const NamedDecl *namedDecl = dyn_cast<NamedDecl>(implDecl);
    if (!namedDecl) {
      assert(false);
      return;
    }
    std::string name = namedDecl->getNameAsString();

    // obtain the map of facts for the current class implementation, possibly a new one
    ObjCImplFacts &facts = _implFacts[name];

    for (ObjCImplDecl::method_iterator it = implDecl->meth_begin(), end = implDecl->meth_end();
         it != end; ++it) {
      FactFinder factFinder(*it, facts);

      factFinder.VisitMethodDecl();

      Stmt *body = (*it)->getBody();
      if (body) {
        factFinder.Visit(body);
      }
    }

    PathDiagnosticLocation pLoc(implDecl->getLocation(), bugReporter.getSourceManager());
    const std::function<void(StringRef)> emitBug([implDecl, &pLoc, &bugReporter, this](StringRef str) {
      bugReporter.EmitBasicReport(implDecl,
                                  this,
                                  "Leaking unsafe reference to self",
                                  "Memory error (Facebook)",
                                  str,
                                  pLoc);
    });

    // The default dealloc in ARC mode does not clear delegates.
    if (!facts._hasDealloc && manager.getLangOpts().ObjCAutoRefCount) {

      const StringSet emptySet;
      for (auto it = facts._ivarFactsMap.begin(), end = facts._ivarFactsMap.end(); it != end; it++) {
        verifyAndReportDangerousProperties(it->second._mayStoreSelfInUnsafeProperty,
                                           emptySet,
                                           it->first->getNameAsString(),
                                           it->first->getType(),
                                           "ARC-generated dealloc",
                                           emitBug);
      }
    }

  }
Exemplo n.º 10
0
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.º 11
0
 void FunctionChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
   if (TD->hasAttr<CMSThreadSafeAttr>())
     return;
   const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
   if (!support::isCmsLocalFile(sfile))
     return;
   std::string fname(sfile);
   if (!support::isInterestingLocation(fname))
     return;
   for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
     if (I->doesThisDeclarationHaveABody()) {
       FWalker walker(this, BR, mgr.getAnalysisDeclContext(*I));
       walker.Visit(I->getBody());
     }
   }
   return;
 }
Exemplo n.º 12
0
void FunctionChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager& mgr,
                    BugReporter &BR) const {

	if ( TD->hasAttr<CMSThreadSafeAttr>()) return;
 	const char *sfile=BR.getSourceManager().getPresumedLoc(TD->getLocation ()).getFilename();
   	if (!support::isCmsLocalFile(sfile)) return;
	std::string fname(sfile);
	if ( fname.find("/test/") != std::string::npos) return;
	for (FunctionTemplateDecl::spec_iterator I = const_cast<clang::FunctionTemplateDecl *>(TD)->spec_begin(), 
			E = const_cast<clang::FunctionTemplateDecl *>(TD)->spec_end(); I != E; ++I) 
		{
			if (I->doesThisDeclarationHaveABody()) {
				FWalker walker(BR, mgr.getAnalysisDeclContext(*I));
				walker.Visit(I->getBody());
				}
		}
	return;
}
Exemplo n.º 13
0
static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
                               const ObjCMethodDecl *MethAncestor,
                               BugReporter &BR, ASTContext &Ctx,
                               const ObjCImplementationDecl *ID) {

  QualType ResDerived  = MethDerived->getResultType();
  QualType ResAncestor = MethAncestor->getResultType();

  if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
    std::string sbuf;
    llvm::raw_string_ostream os(sbuf);

    os << "The Objective-C class '"
       << *MethDerived->getClassInterface()
       << "', which is derived from class '"
       << *MethAncestor->getClassInterface()
       << "', defines the instance method '";
    MethDerived->getSelector().print(os);
    os << "' whose return type is '"
       << ResDerived.getAsString()
       << "'.  A method with the same name (same selector) is also defined in "
          "class '"
       << *MethAncestor->getClassInterface()
       << "' and has a return type of '"
       << ResAncestor.getAsString()
       << "'.  These two types are incompatible, and may result in undefined "
          "behavior for clients of these classes.";

    PathDiagnosticLocation MethDLoc =
      PathDiagnosticLocation::createBegin(MethDerived,
                                          BR.getSourceManager());

    BR.EmitBasicReport(MethDerived,
                       "Incompatible instance method return type",
                       categories::CoreFoundationObjectiveC,
                       os.str(), MethDLoc);
  }
}
void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
                                              BugReporter &B,
                                              ExprEngine &Eng) const {
  CFGBlocksSet reachable, visited;

  if (Eng.hasWorkRemaining())
    return;

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

    if (!D)
      D = LC->getAnalysisDeclContext()->getDecl();

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

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

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

  // Don't do anything for template instantiations.  Proving that code
  // in a template instantiation is unreachable means proving that it is
  // unreachable in all instantiations.
  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
    if (FD->isTemplateInstantiation())
      return;

  // 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 (isInvalidPath(CB, *PM))
      continue;

    // It is good practice to always have a "default" label in a "switch", even
    // if we should never get there. It can be used to detect errors, for
    // instance. Unreachable code directly under a "default" label is therefore
    // likely to be a false positive.
    if (const Stmt *label = CB->getLabel())
      if (label->getStmtClass() == Stmt::DefaultStmtClass)
        continue;

    // Special case for __builtin_unreachable.
    // FIXME: This should be extended to include other unreachable markers,
    // such as llvm_unreachable.
    if (!CB->empty()) {
      bool foundUnreachable = false;
      for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
           ci != ce; ++ci) {
        if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
          if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
            if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
                CE->isBuiltinAssumeFalse(Eng.getContext())) {
              foundUnreachable = true;
              break;
            }
          }
      }
      if (foundUnreachable)
        continue;
    }

    // We found a block that wasn't covered - find the statement to report
    SourceRange SR;
    PathDiagnosticLocation DL;
    SourceLocation SL;
    if (const Stmt *S = getUnreachableStmt(CB)) {
      // In macros, 'do {...} while (0)' is often used. Don't warn about the
      // condition 0 when it is unreachable.
      if (S->getBeginLoc().isMacroID())
        if (const auto *I = dyn_cast<IntegerLiteral>(S))
          if (I->getValue() == 0ULL)
            if (const Stmt *Parent = PM->getParent(S))
              if (isa<DoStmt>(Parent))
                continue;
      SR = S->getSourceRange();
      DL = PathDiagnosticLocation::createBegin(S, B.getSourceManager(), LC);
      SL = DL.asLocation();
      if (SR.isInvalid() || !SL.isValid())
        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(D, this, "Unreachable code", "Dead code",
                      "This statement is never executed", DL, SR);
  }
}
Exemplo n.º 15
0
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.º 16
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);
    }
  }
}
Exemplo n.º 17
0
static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
                                BugReporter &BR) {

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

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

    const ObjCIvarDecl *ID = *I;

    // Ignore ivars that...
    // (a) aren't private
    // (b) explicitly marked unused
    // (c) are iboutlets
    // (d) are unnamed bitfields
    if (ID->getAccessControl() != ObjCIvarDecl::Private ||
        ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
        ID->getAttr<IBOutletCollectionAttr>() ||
        ID->isUnnamedBitfield())
      continue;

    M[ID] = Unused;
  }

  if (M.empty())
    return;

  // Now scan the implementation declaration.
  Scan(M, D);

  // Any potentially unused ivars?
  bool hasUnused = false;
  for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
    if (I->second == Unused) {
      hasUnused = true;
      break;
    }

  if (!hasUnused)
    return;

  // We found some potentially unused ivars.  Scan the entire translation unit
  // for functions inside the @implementation that reference these ivars.
  // FIXME: In the future hopefully we can just use the lexical DeclContext
  // to go from the ObjCImplementationDecl to the lexically "nested"
  // C functions.
  SourceManager &SM = BR.getSourceManager();
  Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);

  // Find ivars that are unused.
  for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
    if (I->second == Unused) {
      std::string sbuf;
      llvm::raw_string_ostream os(sbuf);
      os << "Instance variable '" << *I->first << "' in class '" << *ID
         << "' is never used by the methods in its @implementation "
            "(although it may be used by category methods).";

      PathDiagnosticLocation L =
        PathDiagnosticLocation::create(I->first, BR.getSourceManager());
      BR.EmitBasicReport(D, "Unused instance variable", "Optimization",
                         os.str(), L);
    }
}
Exemplo n.º 18
0
void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
                                            BugReporter &B,
                                            ExprEngine &Eng) const {
  const CFG *C  = 0;
  const SourceManager &SM = B.getSourceManager();
  llvm::SmallPtrSet<const CFGBlock*, 256> reachable;

  // Root node should have the location context of the top most function.
  const ExplodedNode *GraphRoot = *G.roots_begin();
  const LocationContext *LC = GraphRoot->getLocation().getLocationContext();

  const Decl *D = LC->getDecl();

  // Iterate over the exploded graph.
  for (ExplodedGraph::node_iterator I = G.nodes_begin();
      I != G.nodes_end(); ++I) {
    const ProgramPoint &P = I->getLocation();

    // Only check the coverage in the top level function (optimization).
    if (D != P.getLocationContext()->getDecl())
      continue;

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

  // Get the CFG and the Decl of this block.
  C = LC->getCFG();

  unsigned total = 0, unreachable = 0;

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

  // We never 'reach' the entry block, so correct the unreachable count
  unreachable--;
  // There is no BlockEntrance corresponding to the exit block as well, so
  // assume it is reached as well.
  unreachable--;

  // Generate the warning string
  SmallString<128> buf;
  llvm::raw_svector_ostream output(buf);
  PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
  if (!Loc.isValid())
    return;

  if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
    const NamedDecl *ND = cast<NamedDecl>(D);
    output << *ND;
  }
  else if (isa<BlockDecl>(D)) {
    output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
  }

  NumBlocksUnreachable += unreachable;
  NumBlocks += total;
  std::string NameOfRootFunction = output.str();

  output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
      << unreachable << " | Exhausted Block: "
      << (Eng.wasBlocksExhausted() ? "yes" : "no")
      << " | Empty WorkList: "
      << (Eng.hasEmptyWorkList() ? "yes" : "no");

  B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics",
                    output.str(), PathDiagnosticLocation(D, SM));

  // Emit warning for each block we bailed out on.
  typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
  const CoreEngine &CE = Eng.getCoreEngine();
  for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
      E = CE.blocks_exhausted_end(); I != E; ++I) {
    const BlockEdge &BE =  I->first;
    const CFGBlock *Exit = BE.getDst();
    const CFGElement &CE = Exit->front();
    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
      SmallString<128> bufI;
      llvm::raw_svector_ostream outputI(bufI);
      outputI << "(" << NameOfRootFunction << ")" <<
                 ": The analyzer generated a sink at this point";
      B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(),
                        PathDiagnosticLocation::createBegin(CS->getStmt(),
                                                            SM, LC));
    }
  }
}
Exemplo n.º 19
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.º 20
0
void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
        BugReporter &B,
        ExprEngine &Eng) const {
    const CFG *C  = 0;
    const Decl *D = 0;
    const LocationContext *LC = 0;
    const SourceManager &SM = B.getSourceManager();
    llvm::SmallPtrSet<const CFGBlock*, 256> reachable;

    // Iterate over explodedgraph
    for (ExplodedGraph::node_iterator I = G.nodes_begin();
            I != G.nodes_end(); ++I) {
        const ProgramPoint &P = I->getLocation();
        // Save the LocationContext if we don't have it already
        if (!LC)
            LC = P.getLocationContext();

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

    // Get the CFG and the Decl of this block
    C = LC->getCFG();
    D = LC->getAnalysisContext()->getDecl();

    unsigned total = 0, unreachable = 0;

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

    // We never 'reach' the entry block, so correct the unreachable count
    unreachable--;

    // Generate the warning string
    llvm::SmallString<128> buf;
    llvm::raw_svector_ostream output(buf);
    PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
    if (Loc.isValid()) {
        output << Loc.getFilename() << " : ";

        if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
            const NamedDecl *ND = cast<NamedDecl>(D);
            output << ND;
        }
        else if (isa<BlockDecl>(D)) {
            output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
        }
    }

    output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
           << unreachable << " | Exhausted Block: "
           << (Eng.wasBlocksExhausted() ? "yes" : "no")
           << " | Empty WorkList: "
           << (Eng.hasEmptyWorkList() ? "yes" : "no");

    B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
                      PathDiagnosticLocation(D, SM));

    // Emit warning for each block we bailed out on
    typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
    const CoreEngine &CE = Eng.getCoreEngine();
    for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
            E = CE.blocks_exhausted_end(); I != E; ++I) {
        const BlockEdge &BE =  I->first;
        const CFGBlock *Exit = BE.getDst();
        const CFGElement &CE = Exit->front();
        if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
            B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
                              "stopped analyzing at this point",
                              PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
    }
}
Exemplo n.º 21
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.º 22
0
void FunctionChecker::checkASTDecl(const FunctionDecl *FD, AnalysisManager& mgr,
                    BugReporter &BR) const {
	if ( FD->hasAttr<CMSThreadSafeAttr>()) return;
        if (FD-> isInExternCContext()) {
                std::string buf;
                std::string dname = FD->getQualifiedNameAsString();
                if ( dname.compare(dname.size()-1,1,"_") != 0 ) return;
                llvm::raw_string_ostream os(buf);
                os << "function '"<< dname << "' is in an extern \"C\" context and most likely accesses or modifies fortran variables in a 'COMMONBLOCK'.\n";
                clang::ento::PathDiagnosticLocation FDLoc = clang::ento::PathDiagnosticLocation::createBegin(FD, BR.getSourceManager());
		BR.EmitBasicReport(FD, "FunctionChecker : COMMONBLOCK variable accessed or modified","ThreadSafety",os.str(), FDLoc);
                std::string ostring =  "function '" + dname + "' static variable 'COMMONBLOCK'.\n";
		const char * pPath = std::getenv("LOCALRT");
		std::string tname = ""; 
		if ( pPath != NULL ) tname += std::string(pPath);
		tname+="/tmp/function-checker.txt.unsorted";
		std::ofstream file(tname.c_str(),std::ios::app);
		file<<ostring;
        }
}