Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:26:52

0001 #include <clang/AST/DeclCXX.h>
0002 #include <clang/AST/Attr.h>
0003 #include <clang/AST/Decl.h>
0004 #include <clang/AST/DeclTemplate.h>
0005 #include <clang/AST/StmtVisitor.h>
0006 #include <clang/AST/ParentMap.h>
0007 #include <clang/Analysis/CFGStmtMap.h>
0008 #include <clang/Analysis/CallGraph.h>
0009 #include <llvm/Support/SaveAndRestore.h>
0010 #include <clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h>
0011 #include <clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h>
0012 #include <clang/StaticAnalyzer/Core/Checker.h>
0013 #include <clang/StaticAnalyzer/Core/BugReporter/BugReporter.h>
0014 #include <clang/StaticAnalyzer/Core/BugReporter/BugType.h>
0015 #include <llvm/ADT/SmallString.h>
0016 #include <iostream>
0017 #include <fstream>
0018 #include <iterator>
0019 #include <string>
0020 #include <algorithm>
0021 
0022 #include "FunctionChecker.h"
0023 
0024 using namespace clang;
0025 using namespace ento;
0026 using namespace llvm;
0027 
0028 namespace clangcms {
0029 
0030   class FWalker : public clang::StmtVisitor<FWalker> {
0031     const CheckerBase *Checker;
0032     clang::ento::BugReporter &BR;
0033     clang::AnalysisDeclContext *AC;
0034 
0035   public:
0036     FWalker(const CheckerBase *checker, clang::ento::BugReporter &br, clang::AnalysisDeclContext *ac)
0037         : Checker(checker), BR(br), AC(ac) {}
0038 
0039     const clang::Stmt *ParentStmt(const Stmt *S) {
0040       const Stmt *P = AC->getParentMap().getParentIgnoreParens(S);
0041       if (!P)
0042         return nullptr;
0043       return P;
0044     }
0045 
0046     void VisitChildren(clang::Stmt *S);
0047     void VisitStmt(clang::Stmt *S) { VisitChildren(S); }
0048     void VisitDeclRefExpr(clang::DeclRefExpr *DRE);
0049     void ReportDeclRef(const clang::DeclRefExpr *DRE);
0050   };
0051 
0052   void FWalker::VisitChildren(clang::Stmt *S) {
0053     for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I)
0054       if (clang::Stmt *child = *I) {
0055         Visit(child);
0056       }
0057   }
0058 
0059   void FWalker::VisitDeclRefExpr(clang::DeclRefExpr *DRE) {
0060     if (const clang::VarDecl *D = llvm::dyn_cast_or_null<clang::VarDecl>(DRE->getDecl())) {
0061       if (D && support::isSafeClassName(D->getCanonicalDecl()->getQualifiedNameAsString()))
0062         return;
0063       ReportDeclRef(DRE);
0064     }
0065   }
0066 
0067   void FWalker::ReportDeclRef(const clang::DeclRefExpr *DRE) {
0068     const clang::VarDecl *D = llvm::dyn_cast_or_null<clang::VarDecl>(DRE->getDecl());
0069     if (D && (D->hasAttr<CMSThreadGuardAttr>() || D->hasAttr<CMSThreadSafeAttr>()) || D->hasAttr<CMSSaAllowAttr>())
0070       return;
0071     if (support::isSafeClassName(D->getCanonicalDecl()->getQualifiedNameAsString()))
0072       return;
0073 
0074     const char *sfile = BR.getSourceManager().getPresumedLoc(D->getLocation()).getFilename();
0075     std::string fname(sfile);
0076     if (!support::isInterestingLocation(fname))
0077       return;
0078     clang::QualType t = D->getType();
0079     if (support::isSafeClassName(t.getCanonicalType().getAsString()))
0080       return;
0081     const Decl *PD = AC->getDecl();
0082     std::string dname = "";
0083     std::string sdname = "";
0084     if (const NamedDecl *ND = llvm::dyn_cast_or_null<NamedDecl>(PD)) {
0085       sdname = support::getQualifiedName(*ND);
0086       dname = ND->getQualifiedNameAsString();
0087     }
0088     clang::ento::PathDiagnosticLocation DLoc;
0089     if (support::isCmsLocalFile(sfile)) {
0090       if (D->getLocation().isMacroID())
0091         DLoc = clang::ento::PathDiagnosticLocation(D->getLocation(), BR.getSourceManager());
0092       else
0093         DLoc = clang::ento::PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
0094     } else
0095       DLoc = clang::ento::PathDiagnosticLocation::createBegin(DRE, BR.getSourceManager(), AC);
0096 
0097     std::string tname = "function-checker.txt.unsorted";
0098 
0099     std::string vname = support::getQualifiedName(*D);
0100     std::string svname = D->getNameAsString();
0101     if (D->getTSCSpec() == clang::ThreadStorageClassSpecifier::TSCS_thread_local)
0102       return;
0103     if (D->isStaticLocal() && !clangcms::support::isConst(t)) {
0104       std::string buf;
0105       llvm::raw_string_ostream os(buf);
0106       os << "function '" << dname << "' accesses or modifies non-const static local variable '" << svname << "'.\n";
0107       //        BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc);
0108       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0109       support::writeLog(ostring, tname);
0110       return;
0111     }
0112 
0113     if (D->isStaticDataMember() && !clangcms::support::isConst(t)) {
0114       std::string buf;
0115       llvm::raw_string_ostream os(buf);
0116       os << "function '" << dname << "' accesses or modifies non-const static member data variable '" << svname
0117          << "'.\n";
0118       //        BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc);
0119       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0120       support::writeLog(ostring, tname);
0121       return;
0122     }
0123 
0124     if (D->hasGlobalStorage() && !D->isStaticDataMember() && !D->isStaticLocal() && !clangcms::support::isConst(t)) {
0125       std::string buf;
0126       llvm::raw_string_ostream os(buf);
0127       os << "function '" << dname << "' accesses or modifies non-const global static variable '" << svname << "'.\n";
0128       //        BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc);
0129       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0130       support::writeLog(ostring, tname);
0131       return;
0132     }
0133   }
0134 
0135   void FunctionChecker::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager &mgr, BugReporter &BR) const {
0136     if (MD->hasAttr<CMSThreadSafeAttr>() || MD->hasAttr<CMSSaAllowAttr>())
0137       return;
0138     const char *sfile = BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
0139     if (!support::isCmsLocalFile(sfile))
0140       return;
0141     std::string fname(sfile);
0142     if (!support::isInterestingLocation(fname))
0143       return;
0144     if (!MD->doesThisDeclarationHaveABody())
0145       return;
0146     FWalker walker(this, BR, mgr.getAnalysisDeclContext(MD));
0147     walker.Visit(MD->getBody());
0148     return;
0149   }
0150 
0151   void FunctionChecker::checkASTDecl(const FunctionDecl *FD, AnalysisManager &mgr, BugReporter &BR) const {
0152     if (FD->hasAttr<CMSThreadSafeAttr>() || FD->hasAttr<CMSSaAllowAttr>())
0153       return;
0154     if (FD->isInExternCContext()) {
0155       std::string buf;
0156       std::string dname = FD->getQualifiedNameAsString();
0157       if (dname.compare(dname.size() - 1, 1, "_") == 0) {
0158         llvm::raw_string_ostream os(buf);
0159         os << "function '" << dname
0160            << "' is in an extern \"C\" context and most likely accesses or modifies fortran variables in a "
0161               "'COMMONBLOCK'.\n";
0162         clang::ento::PathDiagnosticLocation::createBegin(FD, BR.getSourceManager());
0163         //      BR.EmitBasicReport(FD, "COMMONBLOCK variable accessed or modified","ThreadSafety",os.str(), FDLoc);
0164         std::string ostring = "function '" + dname + "' static variable 'COMMONBLOCK'.\n";
0165         std::string tname = "function-checker.txt.unsorted";
0166         support::writeLog(ostring, tname);
0167       }
0168     }
0169 
0170     const char *sfile = BR.getSourceManager().getPresumedLoc(FD->getLocation()).getFilename();
0171     if (!support::isCmsLocalFile(sfile))
0172       return;
0173     std::string fname(sfile);
0174     if (!support::isInterestingLocation(fname))
0175       return;
0176     if (FD->doesThisDeclarationHaveABody()) {
0177       FWalker walker(this, BR, mgr.getAnalysisDeclContext(FD));
0178       walker.Visit(FD->getBody());
0179     }
0180   }
0181 
0182   void FunctionChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
0183     if (TD->hasAttr<CMSThreadSafeAttr>() || TD->hasAttr<CMSSaAllowAttr>())
0184       return;
0185     const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
0186     if (!support::isCmsLocalFile(sfile))
0187       return;
0188     std::string fname(sfile);
0189     if (!support::isInterestingLocation(fname))
0190       return;
0191     for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
0192       if (I->doesThisDeclarationHaveABody()) {
0193         FWalker walker(this, BR, mgr.getAnalysisDeclContext(*I));
0194         walker.Visit(I->getBody());
0195       }
0196     }
0197     return;
0198   }
0199 
0200 }  // namespace clangcms