Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:31:50

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,
0108                          Checker->getCheckerName(),
0109                          "non-const static local variable accessed or modified",
0110                          "ThreadSafety",
0111                          os.str(),
0112                          DLoc);
0113       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0114       support::writeLog(ostring, tname);
0115       return;
0116     }
0117 
0118     if (D->isStaticDataMember() && !clangcms::support::isConst(t)) {
0119       std::string buf;
0120       llvm::raw_string_ostream os(buf);
0121       os << "function '" << dname << "' accesses or modifies non-const static member data variable '" << svname
0122          << "'.\n";
0123       BR.EmitBasicReport(D,
0124                          Checker->getCheckerName(),
0125                          "non-const static local variable accessed or modified",
0126                          "ThreadSafety",
0127                          os.str(),
0128                          DLoc);
0129       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0130       support::writeLog(ostring, tname);
0131       return;
0132     }
0133 
0134     if (D->hasGlobalStorage() && !D->isStaticDataMember() && !D->isStaticLocal() && !clangcms::support::isConst(t)) {
0135       std::string buf;
0136       llvm::raw_string_ostream os(buf);
0137       os << "function '" << dname << "' accesses or modifies non-const global static variable '" << svname << "'.\n";
0138       BR.EmitBasicReport(D,
0139                          Checker->getCheckerName(),
0140                          "non-const static local variable accessed or modified",
0141                          "ThreadSafety",
0142                          os.str(),
0143                          DLoc);
0144       std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n";
0145       support::writeLog(ostring, tname);
0146       return;
0147     }
0148   }
0149 
0150   void FunctionChecker::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager &mgr, BugReporter &BR) const {
0151     if (MD->hasAttr<CMSThreadSafeAttr>() || MD->hasAttr<CMSSaAllowAttr>())
0152       return;
0153     const char *sfile = BR.getSourceManager().getPresumedLoc(MD->getLocation()).getFilename();
0154     if (!support::isCmsLocalFile(sfile))
0155       return;
0156     std::string fname(sfile);
0157     if (!support::isInterestingLocation(fname))
0158       return;
0159     if (!MD->doesThisDeclarationHaveABody())
0160       return;
0161     FWalker walker(this, BR, mgr.getAnalysisDeclContext(MD));
0162     walker.Visit(MD->getBody());
0163     return;
0164   }
0165 
0166   void FunctionChecker::checkASTDecl(const FunctionDecl *FD, AnalysisManager &mgr, BugReporter &BR) const {
0167     if (FD->hasAttr<CMSThreadSafeAttr>() || FD->hasAttr<CMSSaAllowAttr>())
0168       return;
0169     if (FD->isInExternCContext()) {
0170       std::string buf;
0171       std::string dname = FD->getQualifiedNameAsString();
0172       if (dname.compare(dname.size() - 1, 1, "_") == 0) {
0173         llvm::raw_string_ostream os(buf);
0174         os << "function '" << dname
0175            << "' is in an extern \"C\" context and most likely accesses or modifies fortran variables in a "
0176               "'COMMONBLOCK'.\n";
0177         clang::ento::PathDiagnosticLocation FDLoc =
0178             clang::ento::PathDiagnosticLocation::createBegin(FD, BR.getSourceManager());
0179         BR.EmitBasicReport(
0180             FD, this->getCheckerName(), "COMMONBLOCK variable accessed or modified", "ThreadSafety", os.str(), FDLoc);
0181         std::string ostring = "function '" + dname + "' static variable 'COMMONBLOCK'.\n";
0182         std::string tname = "function-checker.txt.unsorted";
0183         support::writeLog(ostring, tname);
0184       }
0185     }
0186 
0187     const char *sfile = BR.getSourceManager().getPresumedLoc(FD->getLocation()).getFilename();
0188     if (!support::isCmsLocalFile(sfile))
0189       return;
0190     std::string fname(sfile);
0191     if (!support::isInterestingLocation(fname))
0192       return;
0193     if (FD->doesThisDeclarationHaveABody()) {
0194       FWalker walker(this, BR, mgr.getAnalysisDeclContext(FD));
0195       walker.Visit(FD->getBody());
0196     }
0197   }
0198 
0199   void FunctionChecker::checkASTDecl(const FunctionTemplateDecl *TD, AnalysisManager &mgr, BugReporter &BR) const {
0200     if (TD->hasAttr<CMSThreadSafeAttr>() || TD->hasAttr<CMSSaAllowAttr>())
0201       return;
0202     const char *sfile = BR.getSourceManager().getPresumedLoc(TD->getLocation()).getFilename();
0203     if (!support::isCmsLocalFile(sfile))
0204       return;
0205     std::string fname(sfile);
0206     if (!support::isInterestingLocation(fname))
0207       return;
0208     for (auto I = TD->spec_begin(), E = TD->spec_end(); I != E; ++I) {
0209       if (I->doesThisDeclarationHaveABody()) {
0210         FWalker walker(this, BR, mgr.getAnalysisDeclContext(*I));
0211         walker.Visit(I->getBody());
0212       }
0213     }
0214     return;
0215   }
0216 
0217 }  // namespace clangcms