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; }
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; }
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); } }
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); } } } }
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; }
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); } }
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); } } } }
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()); }