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;
 }
Beispiel #2
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;
} 
Beispiel #3
0
 void TrunCastChecker::checkASTDecl(const CXXRecordDecl *D, AnalysisManager &Mgr, BugReporter &BR) const {
   for (auto I = D->method_begin(), E = D->method_end(); I != E; ++I) {
     if (!llvm::isa<clang::CXXMethodDecl>((*I)))
       continue;
     clang::CXXMethodDecl *MD = llvm::cast<clang::CXXMethodDecl>((*I)->getMostRecentDecl());
     if (!MD->hasBody())
       continue;
     clang::Stmt *Body = MD->getBody();
     ICEVisitor icevisitor(this, BR, Mgr.getAnalysisDeclContext(MD));
     icevisitor.Visit(Body);
   }
 }
Beispiel #4
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 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);
      }
    }
  }
}
Beispiel #6
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;
 }
Beispiel #7
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;
}
// 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(
  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.getAnalysisDeclContext(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(D, "malloc() size overflow", categories::UnixAPI,
      "the computation of the size of the memory allocation may overflow",
      PathDiagnosticLocation::createOperatorLoc(i->mulop,
                                                BR.getSourceManager()), &R, 1);
  }
}
Beispiel #9
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);
      }
    }
  }
}
Beispiel #10
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 NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
                                                     AnalysisManager &AM,
                                                     BugReporter &BR) const {
  // Currently this matches CoreFoundation opaque pointer typedefs.
  auto CSuspiciousNumberObjectExprM =
      expr(ignoringParenImpCasts(
          expr(hasType(
              typedefType(hasDeclaration(anyOf(
                  typedefDecl(hasName("CFNumberRef")),
                  typedefDecl(hasName("CFBooleanRef")))))))
          .bind("c_object")));

  // Currently this matches XNU kernel number-object pointers.
  auto CppSuspiciousNumberObjectExprM =
      expr(ignoringParenImpCasts(
          expr(hasType(hasCanonicalType(
              pointerType(pointee(hasCanonicalType(
                  recordType(hasDeclaration(
                      anyOf(
                        cxxRecordDecl(hasName("OSBoolean")),
                        cxxRecordDecl(hasName("OSNumber"))
                            .bind("osnumber"))))))))))
          .bind("cpp_object")));

  // Currently this matches NeXTSTEP number objects.
  auto ObjCSuspiciousNumberObjectExprM =
      expr(ignoringParenImpCasts(
          expr(hasType(hasCanonicalType(
              objcObjectPointerType(pointee(
                  qualType(hasCanonicalType(
                      qualType(hasDeclaration(
                          objcInterfaceDecl(hasName("NSNumber")))))))))))
          .bind("objc_object")));

  auto SuspiciousNumberObjectExprM = anyOf(
      CSuspiciousNumberObjectExprM,
      CppSuspiciousNumberObjectExprM,
      ObjCSuspiciousNumberObjectExprM);

  // Useful for predicates like "Unless we've seen the same object elsewhere".
  auto AnotherSuspiciousNumberObjectExprM =
      expr(anyOf(
          equalsBoundNode("c_object"),
          equalsBoundNode("objc_object"),
          equalsBoundNode("cpp_object")));

  // The .bind here is in order to compose the error message more accurately.
  auto ObjCSuspiciousScalarBooleanTypeM =
      qualType(typedefType(hasDeclaration(
                   typedefDecl(hasName("BOOL"))))).bind("objc_bool_type");

  // The .bind here is in order to compose the error message more accurately.
  auto SuspiciousScalarBooleanTypeM =
      qualType(anyOf(qualType(booleanType()).bind("cpp_bool_type"),
                     ObjCSuspiciousScalarBooleanTypeM));

  // The .bind here is in order to compose the error message more accurately.
  // Also avoid intptr_t and uintptr_t because they were specifically created
  // for storing pointers.
  auto SuspiciousScalarNumberTypeM =
      qualType(hasCanonicalType(isInteger()),
               unless(typedefType(hasDeclaration(
                   typedefDecl(matchesName("^::u?intptr_t$"))))))
      .bind("int_type");

  auto SuspiciousScalarTypeM =
      qualType(anyOf(SuspiciousScalarBooleanTypeM,
                     SuspiciousScalarNumberTypeM));

  auto SuspiciousScalarExprM =
      expr(ignoringParenImpCasts(expr(hasType(SuspiciousScalarTypeM))));

  auto ConversionThroughAssignmentM =
      binaryOperator(allOf(hasOperatorName("="),
                           hasLHS(SuspiciousScalarExprM),
                           hasRHS(SuspiciousNumberObjectExprM)));

  auto ConversionThroughBranchingM =
      ifStmt(allOf(
          hasCondition(SuspiciousNumberObjectExprM),
          unless(hasConditionVariableStatement(declStmt())
      ))).bind("pedantic");

  auto ConversionThroughCallM =
      callExpr(hasAnyArgument(allOf(hasType(SuspiciousScalarTypeM),
                                    ignoringParenImpCasts(
                                        SuspiciousNumberObjectExprM))));

  // We bind "check_if_null" to modify the warning message
  // in case it was intended to compare a pointer to 0 with a relatively-ok
  // construct "x == 0" or "x != 0".
  auto ConversionThroughEquivalenceM =
      binaryOperator(allOf(anyOf(hasOperatorName("=="), hasOperatorName("!=")),
                           hasEitherOperand(SuspiciousNumberObjectExprM),
                           hasEitherOperand(SuspiciousScalarExprM
                                            .bind("check_if_null"))))
      .bind("comparison");

  auto ConversionThroughComparisonM =
      binaryOperator(allOf(anyOf(hasOperatorName(">="), hasOperatorName(">"),
                                 hasOperatorName("<="), hasOperatorName("<")),
                           hasEitherOperand(SuspiciousNumberObjectExprM),
                           hasEitherOperand(SuspiciousScalarExprM)))
      .bind("comparison");

  auto ConversionThroughConditionalOperatorM =
      conditionalOperator(allOf(
          hasCondition(SuspiciousNumberObjectExprM),
          unless(hasTrueExpression(
              hasDescendant(AnotherSuspiciousNumberObjectExprM))),
          unless(hasFalseExpression(
              hasDescendant(AnotherSuspiciousNumberObjectExprM)))))
      .bind("pedantic");

  auto ConversionThroughExclamationMarkM =
      unaryOperator(allOf(hasOperatorName("!"),
                          has(expr(SuspiciousNumberObjectExprM))))
      .bind("pedantic");

  auto ConversionThroughExplicitBooleanCastM =
      explicitCastExpr(allOf(hasType(SuspiciousScalarBooleanTypeM),
                             has(expr(SuspiciousNumberObjectExprM))));

  auto ConversionThroughExplicitNumberCastM =
      explicitCastExpr(allOf(hasType(SuspiciousScalarNumberTypeM),
                             has(expr(SuspiciousNumberObjectExprM))));

  auto ConversionThroughInitializerM =
      declStmt(hasSingleDecl(
          varDecl(hasType(SuspiciousScalarTypeM),
                  hasInitializer(SuspiciousNumberObjectExprM))));

  auto FinalM = stmt(anyOf(ConversionThroughAssignmentM,
                           ConversionThroughBranchingM,
                           ConversionThroughCallM,
                           ConversionThroughComparisonM,
                           ConversionThroughConditionalOperatorM,
                           ConversionThroughEquivalenceM,
                           ConversionThroughExclamationMarkM,
                           ConversionThroughExplicitBooleanCastM,
                           ConversionThroughExplicitNumberCastM,
                           ConversionThroughInitializerM)).bind("conv");

  MatchFinder F;
  Callback CB(this, BR, AM.getAnalysisDeclContext(D));

  F.addMatcher(stmt(forEachDescendant(FinalM)), &CB);
  F.match(*D->getBody(), AM.getASTContext());
}