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 }