Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-19 04:04:57

0001 //===--- CmsSupport.cpp - Provides support functions ------------*- C++ -*-===//
0002 //
0003 // by Shahzad Malik MUZAFFAR [ Shahzad.Malik.MUZAFFAR@cern.ch ]
0004 //
0005 //===----------------------------------------------------------------------===//
0006 #include "CmsSupport.h"
0007 #include <clang/Basic/FileManager.h>
0008 #include <clang/StaticAnalyzer/Core/Checker.h>
0009 #include <clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h>
0010 #include <clang/StaticAnalyzer/Core/BugReporter/BugType.h>
0011 #include <llvm/ADT/SmallString.h>
0012 #include <clang/AST/DeclTemplate.h>
0013 #include <llvm/Support/raw_ostream.h>
0014 #include <llvm/Support/Regex.h>
0015 #include <cstdlib>
0016 #include <cstring>
0017 #include <iostream>
0018 #include <fstream>
0019 #include <iterator>
0020 #include <string>
0021 
0022 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0023 
0024 // PGartung needed for bloom filter loading
0025 extern "C" {
0026 #include "dablooms.h"
0027 #define CAPACITY 5000
0028 #define ERROR_RATE .0002
0029 }
0030 
0031 using namespace clang;
0032 using namespace llvm;
0033 bool clangcms::support::isCmsLocalFile(const char *file) {
0034   static const char *LocalDir = std::getenv("LOCALRT");
0035   CMS_SA_ALLOW static int DirLen = -1;
0036   if (DirLen == -1) {
0037     DirLen = 0;
0038     if (LocalDir != nullptr)
0039       DirLen = strlen(LocalDir);
0040   }
0041   if (strncmp(file, "src/", 4) == 0)
0042     return true;
0043   if ((DirLen == 0) || (strncmp(file, LocalDir, DirLen) != 0) || (strncmp(&file[DirLen], "/src/", 5) != 0))
0044     return false;
0045   return true;
0046 }
0047 
0048 // This is a wrapper around NamedDecl::getQualifiedNameAsString.
0049 // It produces more qualified output to distinguish several cases
0050 // which would otherwise be ambiguous.
0051 std::string clangcms::support::getQualifiedName(const clang::NamedDecl &d) {
0052   std::string ret;
0053   LangOptions LangOpts;
0054   LangOpts.CPlusPlus = true;
0055   PrintingPolicy Policy(LangOpts);
0056   Policy.FullyQualifiedName = true;
0057   Policy.PrintCanonicalTypes = true;
0058   const DeclContext *ctx = d.getDeclContext();
0059   if (ctx->isFunctionOrMethod() && isa<NamedDecl>(ctx)) {
0060     // This is a local variable.
0061     // d.getQualifiedNameAsString() will return the unqualifed name for this
0062     // but we want an actual qualified name so we can distinguish variables
0063     // with the same name but that are in different functions.
0064     ret = getQualifiedName(*cast<NamedDecl>(ctx)) + "::" + d.getNameAsString();
0065   } else {
0066     ret = d.getQualifiedNameAsString();
0067   }
0068 
0069   if (const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(&d)) {
0070     if (fd->isFunctionTemplateSpecialization()) {
0071       ret += "<";
0072       const TemplateArgumentList *TemplateArgs = fd->getTemplateSpecializationArgs();
0073       if (TemplateArgs) {
0074         unsigned num_args = TemplateArgs->size();
0075         for (unsigned i = 0; i < num_args; ++i) {
0076           if (i)
0077             ret += ",";
0078           TemplateArgument TemplateArg = TemplateArgs->get(i);
0079           if (TemplateArg.getKind() == TemplateArgument::ArgKind::Type)
0080             ret += TemplateArg.getAsType().getAsString();
0081         }
0082       }
0083       ret += ">";
0084     }
0085     // This is a function. getQualifiedNameAsString will return a string
0086     // like "ANamespace::AFunction". To this we append the list of parameters
0087     // so that we can distinguish correctly between
0088     // void ANamespace::AFunction(int);
0089     // and
0090     // void ANamespace::AFunction(float);
0091     ret += "(";
0092     const clang::FunctionType *ft = fd->getType()->castAs<clang::FunctionType>();
0093     if (const FunctionProtoType *fpt = dyn_cast_or_null<FunctionProtoType>(ft)) {
0094       unsigned num_params = fd->getNumParams();
0095       for (unsigned i = 0; i < num_params; ++i) {
0096         if (i)
0097           ret += ", ";
0098         ret += fd->getParamDecl(i)->getType().getAsString(Policy);
0099       }
0100 
0101       if (fpt->isVariadic()) {
0102         if (num_params > 0)
0103           ret += ", ";
0104         ret += "...";
0105       }
0106     }
0107     ret += ")";
0108     if (ft->isConst())
0109       ret += " const";
0110   }
0111 
0112   return ret;
0113 }
0114 
0115 bool clangcms::support::isSafeClassName(const std::string &cname) {
0116   static const std::vector<std::string> names = {"atomic<",
0117                                                  "std::atomic<",
0118                                                  "struct std::atomic<",
0119                                                  "std::__atomic_",
0120                                                  "struct std::atomic_flag",
0121                                                  "std::atomic_flag",
0122                                                  "__atomic_flag",
0123                                                  "atomic_flag",
0124                                                  "std::mutex",
0125                                                  "std::recursive_mutex",
0126                                                  "boost::thread_specific_ptr",
0127                                                  "class std::atomic",
0128                                                  "class std::__atomic_",
0129                                                  "class std::mutex",
0130                                                  "class std::recursive_mutex",
0131                                                  "class boost::thread_specific_ptr",
0132                                                  "tbb::",
0133                                                  "class tbb::",
0134                                                  "concurrent_unordered_map",
0135                                                  "class concurrent_unordered_map",
0136                                                  "edm::AtomicPtrCache",
0137                                                  "class edm::AtomicPtrCache",
0138                                                  "edm::InputTag",
0139                                                  "class edm::InputTag",
0140                                                  "std::once_flag",
0141                                                  "struct std::once_flag",
0142                                                  "boost::<anonymous namespace>::extents",
0143                                                  "cout",
0144                                                  "cerr",
0145                                                  "std::cout",
0146                                                  "std::cerr",
0147                                                  "edm::RunningAverage",
0148                                                  "class edm::RunningAverage",
0149                                                  "TVirtualMutex",
0150                                                  "class TVirtualMutex",
0151                                                  "boost::(anonymous namespace)::extents",
0152                                                  "(anonymous namespace)::_1",
0153                                                  "(anonymous namespace)::_2",
0154                                                  "struct PyModuleDef",
0155                                                  "::pybind11::class module_::module_def"};
0156 
0157   for (auto &name : names)
0158     if (cname.substr(0, name.length()) == name)
0159       return true;
0160   return false;
0161 }
0162 
0163 bool clangcms::support::isDataClass(const std::string &name) {
0164   CMS_SA_ALLOW static std::string iname("");
0165   if (iname.empty()) {
0166     clang::FileSystemOptions FSO;
0167     clang::FileManager FM(FSO);
0168     const char *lPath = std::getenv("LOCALRT");
0169     const char *rPath = std::getenv("CMSSW_RELEASE_BASE");
0170     if (lPath == nullptr || rPath == nullptr) {
0171       llvm::errs()
0172           << "\n\nThe scram runtime envorinment is not set.\nRun 'cmsenv' or 'eval `scram runtime -csh`'.\n\n\n";
0173       exit(1);
0174     }
0175     const std::string lname = std::string(lPath);
0176     const std::string rname = std::string(rPath);
0177     const std::string tname("/src/Utilities/StaticAnalyzers/scripts/bloom.bin");
0178     const std::string fname1 = lname + tname;
0179     const std::string fname2 = rname + tname;
0180     if (!(FM.getFile(fname1) || FM.getFile(fname2))) {
0181       llvm::errs() << "\n\nChecker cannot find bloom filter file" << fname1 << " or " << fname2 << "\n\n\n";
0182       exit(1);
0183     }
0184     if (FM.getFile(fname1))
0185       iname = fname1;
0186     else
0187       iname = fname2;
0188   }
0189 
0190   CMS_SA_ALLOW static scaling_bloom_t *blmflt = new_scaling_bloom_from_file(CAPACITY, ERROR_RATE, iname.c_str());
0191 
0192   if (scaling_bloom_check(blmflt, name.c_str(), name.length()) == 1)
0193     return true;
0194 
0195   return false;
0196 }
0197 
0198 bool clangcms::support::isInterestingLocation(const std::string &fname) {
0199   if (fname[0] == '<' && fname.find(".h") == std::string::npos)
0200     return false;
0201   if (fname.find("/test/") != std::string::npos)
0202     return false;
0203   return true;
0204 }
0205 
0206 bool clangcms::support::isKnownThrUnsafeFunc(const std::string &fname) {
0207   static const std::vector<std::string> names = {"TGraph::Fit(const char *,",
0208                                                  "TGraph2D::Fit(const char *,",
0209                                                  "TH1::Fit(const char *,",
0210                                                  "TMultiGraph::Fit(const char *,",
0211                                                  "TTable::Fit(const char *,",
0212                                                  "TTree::Fit(const char *,",
0213                                                  "TTreePlayer::Fit(const char *,",
0214                                                  "CLHEP::HepMatrix::determinant("};
0215   for (auto &name : names)
0216     if (fname.substr(0, name.length()) == name)
0217       return true;
0218   return false;
0219 }
0220 
0221 void clangcms::support::writeLog(const std::string &ostring, const std::string &tfstring) {
0222   const char *pPath = std::getenv("LOCALRT");
0223   if (pPath == nullptr) {
0224     llvm::errs() << "\n\nThe scram runtime envorinment is not set.\nRun 'cmsenv' or 'eval `scram runtime -csh`'.\n\n\n";
0225     exit(1);
0226   }
0227 
0228   std::string pname = std::string(pPath) + "/tmp/";
0229   const std::string tname = pname + tfstring;
0230 
0231   std::fstream file;
0232   file.open(tname.c_str(), std::ios::out | std::ios::app);
0233   file << ostring << "\n";
0234   file.close();
0235 
0236   return;
0237 }
0238 
0239 void clangcms::support::fixAnonNS(std::string &name, const char *fname) {
0240   const std::string anon_ns = "(anonymous namespace)";
0241   if (name.substr(0, anon_ns.size()) == anon_ns) {
0242     const char *sname = "/src/";
0243     const char *filename = std::strstr(fname, sname);
0244     if (filename != nullptr)
0245       name = name.substr(0, anon_ns.size() - 1) + " in " + filename + ")" + name.substr(anon_ns.size());
0246   }
0247   return;
0248 }
0249 
0250 bool clangcms::support::isStdAtomic(const clang::FieldDecl *fieldDecl) {
0251   if (!fieldDecl)
0252     return false;
0253 
0254   // Get the type of the field
0255   clang::QualType fieldType = fieldDecl->getType();
0256 
0257   // Resolve any typedefs or aliases to get the canonical type
0258   fieldType = fieldType.getCanonicalType();
0259 
0260   // Check if the type is a record type (class/struct)
0261   if (const clang::RecordType *recordType = fieldType->getAs<clang::RecordType>()) {
0262     const clang::CXXRecordDecl *recordDecl = clang::dyn_cast<clang::CXXRecordDecl>(recordType->getDecl());
0263     if (!recordDecl)
0264       return false;
0265 
0266     // Check if the record is a class template specialization
0267     if (const clang::ClassTemplateSpecializationDecl *specDecl =
0268             clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
0269       const clang::TemplateDecl *templateDecl = specDecl->getSpecializedTemplate();
0270       if (!templateDecl)
0271         return false;
0272 
0273       // Check if the template name matches "atomic"
0274       const std::string templateName = templateDecl->getNameAsString();
0275       if (templateName == "atomic") {
0276         // Further check if it's in the "std" namespace
0277         const clang::NamespaceDecl *namespaceDecl =
0278             clang::dyn_cast<clang::NamespaceDecl>(templateDecl->getDeclContext());
0279         if (namespaceDecl && namespaceDecl->getNameAsString() == "std") {
0280           return true;
0281         }
0282       }
0283     }
0284   }
0285 
0286   return false;
0287 }