void TUFWalker::VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) { CXXMethodDecl *MD = CE->getMethodDecl(); if (!MD) return; const CXXMethodDecl *PD = llvm::dyn_cast_or_null<CXXMethodDecl>(AC->getDecl()); if (!PD) return; std::string mname = support::getQualifiedName(*MD); std::string pname = support::getQualifiedName(*PD); llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); if (support::isKnownThrUnsafeFunc(mname)) { os << "Known thread unsafe function " << mname << " is called in function " << pname; PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BugType *BT = new BugType(Checker, "known thread unsafe function called", "ThreadSafety"); std::unique_ptr<BugReport> R = llvm::make_unique<BugReport>(*BT, os.str(), CELoc); R->setDeclWithIssue(AC->getDecl()); R->addRange(CE->getSourceRange()); BR.emitReport(std::move(R)); std::string tname = "function-checker.txt.unsorted"; std::string ostring = "function '" + pname + "' known thread unsafe function '" + mname + "'.\n"; support::writeLog(ostring, tname); } }
void gpWalkAST::VisitCXXMemberCallExpr( clang::CXXMemberCallExpr *CE ) { const FunctionDecl * FD = CE->getMethodDecl(); if (!FD) return; std::string mname = FD->getQualifiedNameAsString(); const char *sfile=BR.getSourceManager().getPresumedLoc(CE->getExprLoc()).getFilename(); std::string sname(sfile); if ( ! support::isInterestingLocation(sname) ) return; std::string mdname = ND->getQualifiedNameAsString(); const Expr * IOA = CE->getImplicitObjectArgument(); std::string tname = "getparam-dumper.txt.unsorted"; std::string ps = "const class edm::ParameterSet "; std::string ups = "const class edm::UntrackedParameterSet "; std::string gp = "edm::ParameterSet::getParameter"; std::string gup = "edm::ParameterSet::getUntrackedParameter"; if (mname.substr(0,gp.length()) == gp || mname.substr(0,gup.length()) == gup ) { std::string buf; llvm::raw_string_ostream os(buf); const NamedDecl * nd = llvm::dyn_cast<NamedDecl>(AC->getDecl()); if ( FunctionDecl::classof(ND) ) { os << "function decl '" << nd->getQualifiedNameAsString() ; os << "' this '"<<mdname; } else { os << "constructor decl '" << nd->getQualifiedNameAsString() ; os << "' initializer for member decl '"<<mdname; } clang::LangOptions LangOpts; LangOpts.CPlusPlus = true; clang::PrintingPolicy Policy(LangOpts); os << "' with call args '"; for ( unsigned I=0, E=CE->getNumArgs(); I != E; ++I) { if (I) os <<", "; os << CE->getType().getCanonicalType().getAsString()<<" "; CE->getArg(I)->printPretty(os,0,Policy); } os << "' with implicit object '"; const Expr * E = IOA->IgnoreParenCasts(); QualType QE = E->getType().getCanonicalType(); os << QE.getAsString()<<" "; switch( E->getStmtClass() ) { case Stmt::MemberExprClass: os << dyn_cast<MemberExpr>(E)->getMemberDecl()->getQualifiedNameAsString(); break; case Stmt::DeclRefExprClass: os << dyn_cast<DeclRefExpr>(E)->getDecl()->getQualifiedNameAsString(); break; case Stmt::CXXOperatorCallExprClass: dyn_cast<CXXOperatorCallExpr>(E)->printPretty(os,0,Policy); break; case Stmt::CXXBindTemporaryExprClass: dyn_cast<CXXBindTemporaryExpr>(E)->printPretty(os,0,Policy); break; case Stmt::CXXMemberCallExprClass: dyn_cast<CXXMemberCallExpr>(E)->printPretty(os,0,Policy); break; case Stmt::UnaryOperatorClass: dyn_cast<UnaryOperator>(E)->printPretty(os,0,Policy); break; default: E->printPretty(os,0,Policy); os << " unhandled expr class " <<E->getStmtClassName(); } os<<"'\n"; support::writeLog(os.str(),tname); } return ; }
void FWalker::ReportDeclRef(const clang::DeclRefExpr *DRE) { const clang::VarDecl *D = llvm::dyn_cast_or_null<clang::VarDecl>(DRE->getDecl()); if (D && (D->hasAttr<CMSThreadGuardAttr>() || D->hasAttr<CMSThreadSafeAttr>())) return; if (support::isSafeClassName(D->getCanonicalDecl()->getQualifiedNameAsString())) return; const char *sfile = BR.getSourceManager().getPresumedLoc(D->getLocation()).getFilename(); std::string fname(sfile); if (!support::isInterestingLocation(fname)) return; clang::QualType t = D->getType(); if (support::isSafeClassName(t.getCanonicalType().getAsString())) return; const Decl *PD = AC->getDecl(); std::string dname = ""; std::string sdname = ""; if (const NamedDecl *ND = llvm::dyn_cast_or_null<NamedDecl>(PD)) { sdname = support::getQualifiedName(*ND); dname = ND->getQualifiedNameAsString(); } clang::ento::PathDiagnosticLocation DLoc; if (support::isCmsLocalFile(sfile)) { if (D->getLocation().isMacroID()) DLoc = clang::ento::PathDiagnosticLocation(D->getLocation(), BR.getSourceManager()); else DLoc = clang::ento::PathDiagnosticLocation::createBegin(D, BR.getSourceManager()); } else DLoc = clang::ento::PathDiagnosticLocation::createBegin(DRE, BR.getSourceManager(), AC); std::string tname = "function-checker.txt.unsorted"; std::string vname = support::getQualifiedName(*D); std::string svname = D->getNameAsString(); if (D->getTSCSpec() == clang::ThreadStorageClassSpecifier::TSCS_thread_local) return; if (D->isStaticLocal() && !clangcms::support::isConst(t)) { std::string buf; llvm::raw_string_ostream os(buf); os << "function '" << dname << "' accesses or modifies non-const static local variable '" << svname << "'.\n"; // BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n"; support::writeLog(ostring, tname); return; } if (D->isStaticDataMember() && !clangcms::support::isConst(t)) { std::string buf; llvm::raw_string_ostream os(buf); os << "function '" << dname << "' accesses or modifies non-const static member data variable '" << svname << "'.\n"; // BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n"; support::writeLog(ostring, tname); return; } if (D->hasGlobalStorage() && !D->isStaticDataMember() && !D->isStaticLocal() && !clangcms::support::isConst(t)) { std::string buf; llvm::raw_string_ostream os(buf); os << "function '" << dname << "' accesses or modifies non-const global static variable '" << svname << "'.\n"; // BR.EmitBasicReport(D, Checker, "non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n"; support::writeLog(ostring, tname); return; } }
const clang::Stmt *ParentStmt(const Stmt *S) { const Stmt *P = AC->getParentMap().getParentIgnoreParens(S); if (!P) return nullptr; return P; }
void Walker::VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) { LangOptions LangOpts; LangOpts.CPlusPlus = true; PrintingPolicy Policy(LangOpts); const Decl *D = AC->getDecl(); std::string dname = ""; if (const NamedDecl *ND = llvm::dyn_cast_or_null<NamedDecl>(D)) dname = ND->getQualifiedNameAsString(); CXXMethodDecl *MD = CE->getMethodDecl(); if (!MD) return; std::string mname = MD->getQualifiedNameAsString(); // llvm::errs()<<"Parent Decl: '"<<dname<<"'\n"; // llvm::errs()<<"Method Decl: '"<<mname<<"'\n"; // llvm::errs()<<"call expression '"; // CE->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<"'\n"; // if (!MD) return; llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); if (mname == "edm::Event::getByLabel" || mname == "edm::Event::getManyByType") { // if (const CXXRecordDecl * RD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)->getParent() ) { // llvm::errs()<<"class "<<RD->getQualifiedNameAsString()<<"\n"; // llvm::errs()<<"\n"; // } os << "function '"; llvm::dyn_cast<CXXMethodDecl>(D)->getNameForDiagnostic(os, Policy, true); os << "' "; // os<<"call expression '"; // CE->printPretty(os,0,Policy); // os<<"' "; if (mname == "edm::Event::getByLabel") { os << "calls edm::Event::getByLabel with arguments '"; QualType QT; for (auto I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { QT = (*I)->getType(); std::string qtname = QT.getCanonicalType().getAsString(); if (qtname.substr(0, 17) == "class edm::Handle") { // os<<"argument name '"; // (*I)->printPretty(os,0,Policy); // os<<"' "; const CXXRecordDecl *RD = QT->getAsCXXRecordDecl(); std::string rname = RD->getQualifiedNameAsString(); os << rname << " "; const ClassTemplateSpecializationDecl *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); for (unsigned J = 0, F = SD->getTemplateArgs().size(); J != F; ++J) { SD->getTemplateArgs().data()[J].print(Policy, os); os << ", "; } } else { os << " " << qtname << " "; (*I)->printPretty(os, nullptr, Policy); os << ", "; } } os << "'\n"; } else { os << "calls edm::Event::getManyByType with argument '"; QualType QT = (*CE->arg_begin())->getType(); const CXXRecordDecl *RD = QT->getAsCXXRecordDecl(); os << "getManyByType , "; const ClassTemplateSpecializationDecl *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); const TemplateArgument TA = SD->getTemplateArgs().data()[0]; const QualType AQT = TA.getAsType(); const CXXRecordDecl *SRD = AQT->getAsCXXRecordDecl(); os << SRD->getQualifiedNameAsString() << " "; const ClassTemplateSpecializationDecl *SVD = dyn_cast<ClassTemplateSpecializationDecl>(SRD); for (unsigned J = 0, F = SVD->getTemplateArgs().size(); J != F; ++J) { SVD->getTemplateArgs().data()[J].print(Policy, os); os << ", "; } } // llvm::errs()<<os.str()<<"\n"; PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BugType *BT = new BugType(Checker, "edm::getByLabel or edm::getManyByType called", "optional"); std::unique_ptr<BugReport> R = llvm::make_unique<BugReport>(*BT, os.str(), CELoc); R->addRange(CE->getSourceRange()); BR.emitReport(std::move(R)); } else { for (auto I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I) { QualType QT = (*I)->getType(); std::string qtname = QT.getAsString(); // if (qtname.find(" edm::Event") != std::string::npos ) llvm::errs()<<"arg type '" << qtname <<"'\n"; if (qtname == "edm::Event" || qtname == "const edm::Event" || qtname == "edm::Event *" || qtname == "const edm::Event *") { std::string tname; os << "function '" << dname << "' "; os << "calls '"; MD->getNameForDiagnostic(os, Policy, true); os << "' with argument of type '" << qtname << "'\n"; // llvm::errs()<<"\n"; // llvm::errs()<<"call expression passed edm::Event "; // CE->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<" argument name "; // (*I)->printPretty(llvm::errs(),0,Policy); // llvm::errs()<<" "<<qtname<<"\n"; PathDiagnosticLocation CELoc = PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BugType *BT = new BugType(Checker, "function call with argument of type edm::Event", "optional"); std::unique_ptr<BugReport> R = llvm::make_unique<BugReport>(*BT, os.str(), CELoc); R->addRange(CE->getSourceRange()); BR.emitReport(std::move(R)); } } } }
void ICEVisitor::VisitBinaryOperator(BinaryOperator *BO) { const NamedDecl *ACD = dyn_cast_or_null<NamedDecl>(AC->getDecl()); VisitChildren(BO); std::string ename = "EventNumber_t"; clang::Expr *LHS = BO->getLHS(); clang::Expr *RHS = BO->getRHS(); if (!LHS || !RHS) return; std::string lname = LHS->getType().getAsString(); std::string rname = RHS->getType().getAsString(); if (IntegerLiteral::classof(LHS->IgnoreCasts()) || IntegerLiteral::classof(RHS->IgnoreCasts())) return; if (!(lname == ename || rname == ename)) return; if (lname == ename && rname == ename) return; clang::QualType OTy; clang::QualType TTy; if (lname == ename && ImplicitCastExpr::classof(RHS)) { ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(RHS); TTy = BR.getContext().getCanonicalType(LHS->getType()); OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType()); } if (rname == ename && ImplicitCastExpr::classof(LHS)) { ImplicitCastExpr *ICE = dyn_cast_or_null<ImplicitCastExpr>(LHS); TTy = BR.getContext().getCanonicalType(RHS->getType()); OTy = BR.getContext().getCanonicalType(ICE->getSubExprAsWritten()->getType()); } if (TTy.isNull() || OTy.isNull()) return; QualType ToTy = TTy.getUnqualifiedType(); QualType OrigTy = OTy.getUnqualifiedType(); if (!(ToTy->isIntegerType() || ToTy->isFloatingType())) return; if (ToTy->isBooleanType()) return; CharUnits size_otype = BR.getContext().getTypeSizeInChars(OrigTy); CharUnits size_ttype = BR.getContext().getTypeSizeInChars(ToTy); std::string oname = OrigTy.getAsString(); std::string tname = ToTy.getAsString(); if (ToTy->isFloatingType()) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << " . " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to float type", "CMS code rules", os.str(), CELoc, BO->getSourceRange()); } if ((size_otype > size_ttype)) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Cast may result in truncation. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to smaller int type could truncate", "CMS code rules", os.str(), CELoc, BO->getSourceRange()); } if ((size_otype == size_ttype) && (ToTy->hasSignedIntegerRepresentation() && OrigTy->hasUnsignedIntegerRepresentation() || ToTy->hasUnsignedIntegerRepresentation() && OrigTy->hasSignedIntegerRepresentation())) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Changes int sign type. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(BO, BR.getSourceManager(), AC); BR.EmitBasicReport( ACD, CheckName(), "implicit cast ins sign type", "CMS code rules", os.str(), CELoc, BO->getSourceRange()); } return; return; }
void ICEVisitor::VisitImplicitCastExpr(ImplicitCastExpr *CE) { const NamedDecl *ACD = dyn_cast<NamedDecl>(AC->getDecl()); VisitChildren(CE); const Expr *SE = CE->getSubExprAsWritten(); std::string sename = SE->getType().getAsString(); const clang::Expr *E = CE->getSubExpr(); if (!(sename == "EventNumber_t")) return; QualType OTy = BR.getContext().getCanonicalType(E->getType()); QualType TTy = BR.getContext().getCanonicalType(CE->getType()); QualType ToTy = TTy.getUnqualifiedType(); QualType OrigTy = OTy.getUnqualifiedType(); if (!(ToTy->isIntegerType() || ToTy->isFloatingType())) return; if (ToTy->isBooleanType()) return; CharUnits size_otype = BR.getContext().getTypeSizeInChars(OrigTy); CharUnits size_ttype = BR.getContext().getTypeSizeInChars(ToTy); std::string oname = OrigTy.getAsString(); std::string tname = ToTy.getAsString(); if (ToTy->isFloatingType()) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << " . " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to float type", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } if ((size_otype > size_ttype)) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Cast may result in truncation. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast of int type to smaller int type could truncate", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } if (ToTy->hasSignedIntegerRepresentation() && OrigTy->hasUnsignedIntegerRepresentation() || ToTy->hasUnsignedIntegerRepresentation() && OrigTy->hasSignedIntegerRepresentation()) { llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); os << "Cast-to type, " << tname << ". Cast-from type, " << oname << ". Changes int sign type. " << support::getQualifiedName(*(ACD)); clang::ento::PathDiagnosticLocation CELoc = clang::ento::PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); BR.EmitBasicReport(ACD, CheckName(), "implicit cast changes int sign type", "CMS code rules", os.str(), CELoc, CE->getSourceRange()); } return; }
void FWalker::ReportDeclRef ( const clang::DeclRefExpr * DRE) { if (const clang::VarDecl * D = llvm::dyn_cast<clang::VarDecl>(DRE->getDecl())) { if ( D->hasAttr<CMSThreadGuardAttr>() || D->hasAttr<CMSThreadSafeAttr>()) return; if ( support::isSafeClassName( D->getCanonicalDecl()->getQualifiedNameAsString() ) ) return; const char *sfile=BR.getSourceManager().getPresumedLoc(D->getLocation()).getFilename(); std::string fname(sfile); if ( fname.find("stdio.h") != std::string::npos || fname.find("iostream") != std::string::npos || fname.find("placeholders.hpp") != std::string::npos) return; clang::QualType t = D->getType(); const Decl * PD = AC->getDecl(); std::string dname =""; std::string sdname =""; if (const NamedDecl * ND = llvm::dyn_cast<NamedDecl>(PD)) { sdname = support::getQualifiedName(*ND); dname = ND->getQualifiedNameAsString(); } clang::ento::PathDiagnosticLocation DLoc; if (support::isCmsLocalFile(sfile)) { if (D->getLocation().isMacroID()) DLoc = clang::ento::PathDiagnosticLocation(D->getLocation(),BR.getSourceManager()); else DLoc = clang::ento::PathDiagnosticLocation::createBegin(D, BR.getSourceManager()); } else DLoc = clang::ento::PathDiagnosticLocation::createBegin(DRE, BR.getSourceManager(), AC); const char * pPath = std::getenv("LOCALRT"); std::string tname = ""; if ( pPath != NULL ) tname += std::string(pPath); tname+="/tmp/function-checker.txt.unsorted"; std::string vname = support::getQualifiedName(*D); std::string svname = D->getNameAsString(); if ( (D->isStaticLocal() && D->getTSCSpec() != clang::ThreadStorageClassSpecifier::TSCS_thread_local ) && ! clangcms::support::isConst( t ) ) { if ( support::isSafeClassName( t.getAsString() ) ) return; std::string buf; llvm::raw_string_ostream os(buf); os << "function '"<<dname << "' accesses or modifies non-const static local variable '" << svname<< "'.\n"; BR.EmitBasicReport(D, "FunctionChecker : non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '"+ sdname + "' static variable '" + vname + "'.\n"; std::ofstream file(tname.c_str(),std::ios::app); file<<ostring; return; } if ( (D->isStaticDataMember() && D->getTSCSpec() != clang::ThreadStorageClassSpecifier::TSCS_thread_local ) && ! clangcms::support::isConst( t ) ) { std::string buf; llvm::raw_string_ostream os(buf); os << "function '"<<dname<< "' accesses or modifies non-const static member data variable '" << svname << "'.\n"; BR.EmitBasicReport(D, "FunctionChecker : non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n"; std::ofstream file(tname.c_str(),std::ios::app); file<<ostring; return; } if ( D->hasGlobalStorage() && !D->isStaticDataMember() && !D->isStaticLocal() && !clangcms::support::isConst( t ) ) { std::string buf; llvm::raw_string_ostream os(buf); os << "function '"<<dname << "' accesses or modifies non-const global static variable '" << svname << "'.\n"; BR.EmitBasicReport(D, "FunctionChecker : non-const static local variable accessed or modified","ThreadSafety",os.str(), DLoc); std::string ostring = "function '" + sdname + "' static variable '" + vname + "'.\n"; std::ofstream file(tname.c_str(),std::ios::app); file<<ostring; return; } } }