Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-10-08 23:10:07

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)
0070       return;
0071     if ((D->hasAttr<CMSThreadGuardAttr>() || D->hasAttr<CMSThreadSafeAttr>()) || D->hasAttr<CMSSaAllowAttr>())
0072       return;
0073     if (support::isSafeClassName(D->getCanonicalDecl()->getQualifiedNameAsString()))
0074       return;
0075 
0076     const char *sfile = BR.getSourceManager().getPresumedLoc(D->getLocation()).getFilename();
0077     std::string fname(sfile);
0078     if (!support::isInterestingLocation(fname))
0079       return;
0080     clang::QualType t = D->getType();
0081     if (support::isSafeClassName(t.getCanonicalType().getAsString()))
0082       return;
0083     const Decl *PD = AC->getDecl();
0084     std::string dname = "";
0085     std::string sdname = "";
0086     if (const NamedDecl *ND = llvm::dyn_cast_or_null<NamedDecl>(PD)) {
0087       sdname = support::getQualifiedName(*ND);
0088       dname = ND->getQualifiedNameAsString();
0089     }
0090     clang::ento::PathDiagnosticLocation DLoc;
0091     if (support::isCmsLocalFile(sfile)) {
0092       if (D->getLocation().isMacroID())
0093         DLoc = clang::ento::PathDiagnosticLocation(D->getLocation(), BR.getSourceManager());
0094       else
0095         DLoc = clang::ento::PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
0096     } else
0097       DLoc = clang::ento::PathDiagnosticLocation::createBegin(DRE, BR.getSourceManager(), AC);
0098 
0099     std::string tname = "function-checker.txt.unsorted";
0100 
0101     std::string vname = support::getQualifiedName(*D);
0102     std::string svname = D->getNameAsString();
0103     if (D->getTSCSpec() == clang::ThreadStorageClassSpecifier::TSCS_thread_local)
0104       return;
0105     if (D->isStaticLocal() && !clangcms::support::isConst(t)) {
0106       std::string buf;
0107       llvm::raw_string_ostream os(buf);
0108       os << "function '" << dname << "' accesses or modifies non-const static local variable '" << svname << "'.\n";
0109       BR.EmitBasicReport(D,
0110                          Checker->getCheckerName(),
0111                          "non-const static local variable accessed or modified",
0112                          "ThreadSafety",
0113                          os.str(),
0114                          DLoc);
0115       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0116       support::writeLog(ostring, tname);
0117       return;
0118     }
0119 
0120     if (D->isStaticDataMember() && !clangcms::support::isConst(t)) {
0121       std::string buf;
0122       llvm::raw_string_ostream os(buf);
0123       os << "function '" << dname << "' accesses or modifies non-const static member data variable '" << svname
0124          << "'.\n";
0125       BR.EmitBasicReport(D,
0126                          Checker->getCheckerName(),
0127                          "non-const static local variable accessed or modified",
0128                          "ThreadSafety",
0129                          os.str(),
0130                          DLoc);
0131       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0132       support::writeLog(ostring, tname);
0133       return;
0134     }
0135 
0136     if (D->hasGlobalStorage() && !D->isStaticDataMember() && !D->isStaticLocal() && !clangcms::support::isConst(t)) {
0137       std::string buf;
0138       llvm::raw_string_ostream os(buf);
0139       os << "function '" << dname << "' accesses or modifies non-const global static variable '" << svname << "'.\n";
0140       BR.EmitBasicReport(D,
0141                          Checker->getCheckerName(),
0142                          "non-const static local variable accessed or modified",
0143                          "ThreadSafety",
0144                          os.str(),
0145                          DLoc);
0146       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0147       support::writeLog(ostring, tname);
0148       return;
0149     }
0150   }
0151 
0152   void FunctionChecker::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager &mgr, BugReporter &BR) const {
0153     if (MD->hasAttr<CMSThreadSafeAttr>() || MD->hasAttr<CMSSaAllowAttr>())
0154       return;
0155     const char *sfile = BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
0156     if (!support::isCmsLocalFile(sfile))
0157       return;
0158     std::string fname(sfile);
0159     if (!support::isInterestingLocation(fname))
0160       return;
0161     if (!MD->doesThisDeclarationHaveABody())
0162       return;
0163     FWalker walker(this, BR, mgr.getAnalysisDeclContext(MD));
0164     walker.Visit(MD->getBody());
0165     return;
0166   }
0167 
0168   void FunctionChecker::checkASTDecl(const FunctionDecl *FD, AnalysisManager &mgr, BugReporter &BR) const {
0169     if (FD->hasAttr<CMSThreadSafeAttr>() || FD->hasAttr<CMSSaAllowAttr>())
0170       return;
0171     if (FD->isInExternCContext()) {
0172       std::string buf;
0173       std::string dname = FD->getQualifiedNameAsString();
0174       if (dname.compare(dname.size() - 1, 1, "_") == 0) {
0175         llvm::raw_string_ostream os(buf);
0176         os << "function '" << dname
0177            << "' is in an extern \"C\" context and most likely accesses or modifies fortran variables in a "
0178               "'COMMONBLOCK'.\n";
0179         clang::ento::PathDiagnosticLocation FDLoc =
0180             clang::ento::PathDiagnosticLocation::createBegin(FD, BR.getSourceManager());
0181         BR.EmitBasicReport(
0182             FD, this->getCheckerName(), "COMMONBLOCK variable accessed or modified", "ThreadSafety", os.str(), FDLoc);
0183         std::string ostring = "function '" + dname + "' static variable 'COMMONBLOCK'.\n";
0184         std::string tname = "function-checker.txt.unsorted";
0185         support::writeLog(ostring, tname);
0186       }
0187     }
0188 
0189     const char *sfile = BR.getSourceManager().getPresumedLoc(FD->getLocation()).getFilename();
0190     if (!support::isCmsLocalFile(sfile))
0191       return;
0192     std::string fname(sfile);
0193     if (!support::isInterestingLocation(fname))
0194       return;
0195     if (FD->doesThisDeclarationHaveABody()) {
0196       FWalker walker(this, BR, mgr.getAnalysisDeclContext(FD));
0197       walker.Visit(FD->getBody());
0198     }
0199   }
0200 
0201   void FunctionChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
0202     if (TD->hasAttr<CMSThreadSafeAttr>() || TD->hasAttr<CMSSaAllowAttr>())
0203       return;
0204     const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
0205     if (!support::isCmsLocalFile(sfile))
0206       return;
0207     std::string fname(sfile);
0208     if (!support::isInterestingLocation(fname))
0209       return;
0210     for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
0211       if (I->doesThisDeclarationHaveABody()) {
0212         FWalker walker(this, BR, mgr.getAnalysisDeclContext(*I));
0213         walker.Visit(I->getBody());
0214       }
0215     }
0216     return;
0217   }
0218 
0219 }  // namespace clangcms