File indexing completed on 2024-04-06 12:31:51
0001 #include <clang/AST/DeclCXX.h>
0002 #include <clang/AST/ExprCXX.h>
0003 #include <clang/AST/StmtCXX.h>
0004 #include <clang/AST/Decl.h>
0005 #include <clang/AST/DeclTemplate.h>
0006 #include <llvm/ADT/StringSwitch.h>
0007 #include <clang/AST/Decl.h>
0008 #include <clang/AST/Attr.h>
0009 #include <clang/AST/DeclTemplate.h>
0010 #include <clang/AST/DeclCXX.h>
0011 #include <clang/AST/StmtVisitor.h>
0012 #include <clang/AST/ParentMap.h>
0013 #include <clang/Analysis/CFGStmtMap.h>
0014 #include <clang/StaticAnalyzer/Core/Checker.h>
0015 #include <clang/StaticAnalyzer/Core/BugReporter/BugReporter.h>
0016 #include <clang/StaticAnalyzer/Core/BugReporter/BugType.h>
0017 #include <clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h>
0018 #include <llvm/Support/SaveAndRestore.h>
0019 #include <llvm/ADT/SmallString.h>
0020 #include <iostream>
0021 #include <fstream>
0022 #include <iterator>
0023 #include <string>
0024 #include <algorithm>
0025
0026 #include "CmsException.h"
0027 #include "CmsSupport.h"
0028 #include "getParamDumper.h"
0029
0030 using namespace clang;
0031 using namespace ento;
0032 using namespace llvm;
0033
0034 namespace clangcms {
0035
0036 void getParamDumper::analyzerEval(const clang::CallExpr *CE, clang::ento::CheckerContext &C) const {
0037 if (!C.getSourceManager().isInMainFile(CE->getExprLoc()))
0038 return;
0039
0040 const FunctionDecl *FD = CE->getDirectCallee();
0041
0042 if (!FD)
0043 return;
0044
0045 std::string mname = support::getQualifiedName(*FD);
0046 const char *sfile = C.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename();
0047 std::string sname(sfile);
0048 if (!support::isInterestingLocation(sname))
0049 return;
0050 std::string mdname;
0051 const FunctionDecl *MD = C.getCurrentAnalysisDeclContext()->getDecl()->getAsFunction();
0052 if (!MD)
0053 return;
0054 mdname = MD->getQualifiedNameAsString();
0055 for (unsigned I = 0, E = MD->getNumParams(); I != E; ++I) {
0056 std::string ps = "const class edm::ParameterSet ";
0057 std::string ups = "const class edm::UntrackedParameterSet ";
0058 std::string pname = MD->getParamDecl(I)->getQualifiedNameAsString();
0059 std::string qname = MD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0060
0061 std::string buf;
0062 llvm::raw_string_ostream os(buf);
0063 os << "in function decl '" << mdname << "' with parameter '" << qname << " " << pname << "'\n";
0064
0065 }
0066 const CXXMemberCallExpr *CXE = llvm::dyn_cast_or_null<CXXMemberCallExpr>(CE);
0067 if (!CXE)
0068 return;
0069 const Expr *IOA = CXE->getImplicitObjectArgument();
0070 std::string tname = "getparam-dumper.txt.unsorted";
0071 std::string gp = "edm::ParameterSet::getParameter";
0072 std::string gup = "edm::ParameterSet::getUntrackedParameter";
0073 if (mname.substr(0, gp.length()) == gp || mname.substr(0, gup.length()) == gup) {
0074 std::string buf;
0075 llvm::raw_string_ostream os(buf);
0076 os << "in function decl '" << mdname << "' member function call '";
0077 clang::LangOptions LangOpts;
0078 LangOpts.CPlusPlus = true;
0079 clang::PrintingPolicy Policy(LangOpts);
0080 os << support::getQualifiedName(*(CXE->getMethodDecl()));
0081 os << "' with args '";
0082 for (unsigned I = 0, E = CE->getNumArgs(); I != E; ++I) {
0083 if (I)
0084 os << ", ";
0085 CE->getArg(I)->printPretty(os, nullptr, Policy);
0086 }
0087 os << "' with implicit object '";
0088 const Expr *E = IOA->IgnoreParenNoopCasts(C.getASTContext());
0089 QualType QE = E->getType().getCanonicalType();
0090 os << QE.getAsString() << " ";
0091 switch (E->getStmtClass()) {
0092 case Stmt::MemberExprClass:
0093 os << dyn_cast<MemberExpr>(E)->getMemberDecl()->getQualifiedNameAsString();
0094 break;
0095 case Stmt::DeclRefExprClass:
0096 os << dyn_cast<DeclRefExpr>(E)->getDecl()->getQualifiedNameAsString();
0097 break;
0098 case Stmt::CXXOperatorCallExprClass:
0099 dyn_cast<CXXOperatorCallExpr>(E)->printPretty(os, nullptr, Policy);
0100 break;
0101 case Stmt::CXXBindTemporaryExprClass:
0102 dyn_cast<CXXBindTemporaryExpr>(E)->printPretty(os, nullptr, Policy);
0103 break;
0104 case Stmt::CXXMemberCallExprClass:
0105 dyn_cast<CXXMemberCallExpr>(E)->printPretty(os, nullptr, Policy);
0106 break;
0107 case Stmt::UnaryOperatorClass:
0108 dyn_cast<UnaryOperator>(E)->printPretty(os, nullptr, Policy);
0109 break;
0110 default:
0111 E->printPretty(os, nullptr, Policy);
0112 os << " unhandled expr class " << E->getStmtClassName();
0113 }
0114 os << "'\n";
0115
0116 support::writeLog(os.str(), tname);
0117 }
0118 return;
0119 }
0120
0121 bool getParamDumper::evalCall(const CallEvent &Call, CheckerContext &C) const {
0122 const auto *CE = llvm::dyn_cast_or_null<clang::CallExpr>(Call.getOriginExpr());
0123 if (!CE)
0124 return false;
0125
0126 FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
0127 .Case("getParameter", &getParamDumper::analyzerEval)
0128 .Case("getUntrackedParameter", &getParamDumper::analyzerEval)
0129 .Default(nullptr);
0130
0131 if (!Handler)
0132 return false;
0133
0134 (this->*Handler)(CE, C);
0135
0136 return true;
0137 }
0138
0139 class gpWalkAST : public clang::StmtVisitor<gpWalkAST> {
0140 const CheckerBase *Checker;
0141 clang::ento::BugReporter &BR;
0142 clang::AnalysisDeclContext *AC;
0143 const NamedDecl *ND;
0144
0145 public:
0146 gpWalkAST(const CheckerBase *checker,
0147 clang::ento::BugReporter &br,
0148 clang::AnalysisDeclContext *ac,
0149 const NamedDecl *nd)
0150 : Checker(checker), BR(br), AC(ac), ND(nd) {}
0151
0152
0153 void VisitChildren(clang::Stmt *S);
0154 void VisitStmt(clang::Stmt *S) { VisitChildren(S); }
0155 void VisitCXXMemberCallExpr(clang::CXXMemberCallExpr *CE);
0156 };
0157
0158 void gpWalkAST::VisitChildren(clang::Stmt *S) {
0159 for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I)
0160 if (clang::Stmt *child = *I) {
0161 Visit(child);
0162 }
0163 }
0164
0165 void gpWalkAST::VisitCXXMemberCallExpr(clang::CXXMemberCallExpr *CE) {
0166 const FunctionDecl *FD = CE->getMethodDecl();
0167 if (!FD)
0168 return;
0169
0170 std::string mname = FD->getQualifiedNameAsString();
0171 const char *sfile = BR.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename();
0172 std::string sname(sfile);
0173 if (!support::isInterestingLocation(sname))
0174 return;
0175 std::string mdname = ND->getQualifiedNameAsString();
0176 const Expr *IOA = CE->getImplicitObjectArgument();
0177 std::string tname = "getparam-dumper.txt.unsorted";
0178 std::string ps = "const class edm::ParameterSet ";
0179 std::string ups = "const class edm::UntrackedParameterSet ";
0180 std::string gp = "edm::ParameterSet::getParameter";
0181 std::string gup = "edm::ParameterSet::getUntrackedParameter";
0182 if (mname.substr(0, gp.length()) == gp || mname.substr(0, gup.length()) == gup) {
0183 std::string buf;
0184 llvm::raw_string_ostream os(buf);
0185 const NamedDecl *nd = llvm::dyn_cast<NamedDecl>(AC->getDecl());
0186 if (FunctionDecl::classof(ND)) {
0187 os << "function decl '" << nd->getQualifiedNameAsString();
0188 os << "' this '" << mdname;
0189 } else {
0190 os << "constructor decl '" << nd->getQualifiedNameAsString();
0191 os << "' initializer for member decl '" << mdname;
0192 }
0193 clang::LangOptions LangOpts;
0194 LangOpts.CPlusPlus = true;
0195 clang::PrintingPolicy Policy(LangOpts);
0196 os << "' with call args '";
0197 for (unsigned I = 0, E = CE->getNumArgs(); I != E; ++I) {
0198 if (I)
0199 os << ", ";
0200 os << CE->getType().getCanonicalType().getAsString() << " ";
0201 CE->getArg(I)->printPretty(os, nullptr, Policy);
0202 }
0203 os << "' with implicit object '";
0204 const Expr *E = IOA->IgnoreParenCasts();
0205 QualType QE = E->getType().getCanonicalType();
0206 os << QE.getAsString() << " ";
0207 switch (E->getStmtClass()) {
0208 case Stmt::MemberExprClass:
0209 os << dyn_cast<MemberExpr>(E)->getMemberDecl()->getQualifiedNameAsString();
0210 break;
0211 case Stmt::DeclRefExprClass:
0212 os << dyn_cast<DeclRefExpr>(E)->getDecl()->getQualifiedNameAsString();
0213 break;
0214 case Stmt::CXXOperatorCallExprClass:
0215 dyn_cast<CXXOperatorCallExpr>(E)->printPretty(os, nullptr, Policy);
0216 break;
0217 case Stmt::CXXBindTemporaryExprClass:
0218 dyn_cast<CXXBindTemporaryExpr>(E)->printPretty(os, nullptr, Policy);
0219 break;
0220 case Stmt::CXXMemberCallExprClass:
0221 dyn_cast<CXXMemberCallExpr>(E)->printPretty(os, nullptr, Policy);
0222 break;
0223 case Stmt::UnaryOperatorClass:
0224 dyn_cast<UnaryOperator>(E)->printPretty(os, nullptr, Policy);
0225 break;
0226 default:
0227 E->printPretty(os, nullptr, Policy);
0228 os << " unhandled expr class " << E->getStmtClassName();
0229 }
0230 os << "'\n";
0231
0232 support::writeLog(os.str(), tname);
0233 }
0234 return;
0235 }
0236
0237 void getParamDumper::checkASTDecl(const clang::CXXRecordDecl *RD,
0238 clang::ento::AnalysisManager &mgr,
0239 clang::ento::BugReporter &BR) const {
0240 const clang::SourceManager &SM = BR.getSourceManager();
0241 const char *sfile = SM.getPresumedLoc(RD->getLocation()).getFilename();
0242 if (!support::isCmsLocalFile(sfile))
0243 return;
0244
0245 std::string tname = "getparam-dumper.txt.unsorted";
0246 std::string ps = "const class edm::ParameterSet ";
0247 std::string ups = "const class edm::UntrackedParameterSet ";
0248
0249 for (clang::CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end(); I != E; ++I) {
0250 clang::CXXConstructorDecl *CD = llvm::dyn_cast<clang::CXXConstructorDecl>((*I)->getMostRecentDecl());
0251 for (unsigned I = 0, E = CD->getNumParams(); I != E; ++I) {
0252 std::string pname = CD->getParamDecl(I)->getQualifiedNameAsString();
0253 std::string qname = CD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0254 if (qname.substr(0, ps.length()) == ps || qname.substr(0, ups.length()) == ups) {
0255 std::string buf;
0256 llvm::raw_string_ostream os(buf);
0257 os << "constructor decl '" << CD->getQualifiedNameAsString() << "' with parameter '" << qname << " " << pname
0258 << "'\n";
0259 support::writeLog(os.str(), tname);
0260 for (CXXConstructorDecl::init_iterator J = CD->init_begin(), E = CD->init_end(); J != E; ++J) {
0261 if (FieldDecl *fd = (*J)->getAnyMember()) {
0262 std::string fname = fd->getQualifiedNameAsString();
0263 std::string fqname = fd->getType().getCanonicalType().getAsString();
0264 os << "constructor decl '" << CD->getQualifiedNameAsString() << "' initializer for member decl '" << fname
0265 << "' of type '" << fqname << "'\n";
0266 Expr *e = (*J)->getInit();
0267 if (e) {
0268 gpWalkAST walker(this, BR, mgr.getAnalysisDeclContext(CD), fd);
0269 walker.Visit(e);
0270 }
0271 }
0272 }
0273 support::writeLog(os.str(), tname);
0274 }
0275 }
0276 }
0277
0278 for (clang::CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) {
0279 clang::CXXMethodDecl *MD = llvm::cast<clang::CXXMethodDecl>((*I)->getMostRecentDecl());
0280 for (unsigned I = 0, E = MD->getNumParams(); I != E; ++I) {
0281 std::string pname = MD->getParamDecl(I)->getQualifiedNameAsString();
0282 std::string qname = MD->getParamDecl(I)->getType().getCanonicalType().getAsString();
0283 if (qname.substr(0, ps.length()) == ps || qname.substr(0, ups.length()) == ups) {
0284 std::string buf;
0285 llvm::raw_string_ostream os(buf);
0286 clang::Stmt *Body = MD->getBody();
0287 if (Body) {
0288 os << "function decl '" << MD->getQualifiedNameAsString() << "' with parameter '" << qname << " " << pname
0289 << "'\n";
0290 gpWalkAST walker(this, BR, mgr.getAnalysisDeclContext(MD), MD);
0291 walker.Visit(Body);
0292 }
0293 support::writeLog(os.str(), tname);
0294 }
0295 }
0296 }
0297
0298 return;
0299 }
0300
0301 }