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
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
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
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
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 }