Beispiel #1
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;
  }
}
  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);
      }
    }

  }