Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:31:50

0001 //== ConstCastAwayChecker.cpp - Checks for removed const qualfiers --------------*- C++ -*--==//
0002 //
0003 // Check in a generic way if an explicit cast removes a const qualifier.
0004 //
0005 // by Thomas Hauth [ Thomas.Hauth@cern.ch ]
0006 //
0007 //===----------------------------------------------------------------------===//
0008 #include <clang/AST/ExprCXX.h>
0009 #include <clang/AST/Attr.h>
0010 #include <clang/AST/ParentMap.h>
0011 #include <clang/AST/Stmt.h>
0012 
0013 #include <memory>
0014 
0015 #include "ConstCastAwayChecker.h"
0016 #include "CmsSupport.h"
0017 
0018 using namespace clang;
0019 using namespace clang::ento;
0020 using namespace llvm;
0021 
0022 namespace clangcms {
0023 
0024   void ConstCastAwayChecker::checkPreStmt(const clang::ExplicitCastExpr *CE, clang::ento::CheckerContext &C) const {
0025     if (!(clang::CStyleCastExpr::classof(CE) || clang::CXXConstCastExpr::classof(CE)))
0026       return;
0027     auto P = C.getCurrentAnalysisDeclContext()->getParentMap().getParent(CE);
0028     while (P && !(isa<AttributedStmt>(P) || isa<DeclStmt>(P)) &&
0029            C.getCurrentAnalysisDeclContext()->getParentMap().hasParent(P)) {
0030       P = C.getCurrentAnalysisDeclContext()->getParentMap().getParent(P);
0031     }
0032     if (P && isa<AttributedStmt>(P)) {
0033       const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(P);
0034       if (AS && (hasSpecificAttr<CMSSaAllowAttr>(AS->getAttrs()) || hasSpecificAttr<CMSThreadSafeAttr>(AS->getAttrs())))
0035         return;
0036     }
0037     if (P && isa<DeclStmt>(P)) {
0038       const DeclStmt *DS = dyn_cast_or_null<DeclStmt>(P);
0039       if (DS) {
0040         for (auto D : DS->decls()) {
0041           if (hasSpecificAttr<CMSSaAllowAttr>(D->getAttrs()) || hasSpecificAttr<CMSThreadSafeAttr>(D->getAttrs())) {
0042             return;
0043           }
0044         }
0045       }
0046     }
0047 
0048     const Expr *SE = CE->getSubExpr();
0049     const CXXRecordDecl *CRD = nullptr;
0050     std::string cname;
0051     if (SE->getType()->isPointerType())
0052       CRD = SE->getType()->getPointeeCXXRecordDecl();
0053     else
0054       CRD = SE->getType()->getAsCXXRecordDecl();
0055 
0056     if (CRD)
0057       cname = CRD->getQualifiedNameAsString();
0058 
0059     clang::ASTContext &Ctx = C.getASTContext();
0060     clang::QualType OrigTy = Ctx.getCanonicalType(SE->getType());
0061     clang::QualType ToTy = Ctx.getCanonicalType(CE->getType());
0062 
0063     if (support::isConst(OrigTy) && !support::isConst(ToTy)) {
0064       if (clang::ento::ExplodedNode *errorNode = C.generateErrorNode()) {
0065         if (!BT)
0066           BT = std::make_unique<clang::ento::BugType>(this, "const cast away", "ConstThreadSafety");
0067         std::string buf;
0068         llvm::raw_string_ostream os(buf);
0069         os << "const qualifier was removed via a cast, this may result in thread-unsafe code.";
0070         std::unique_ptr<clang::ento::PathSensitiveBugReport> PSBR =
0071             std::make_unique<clang::ento::PathSensitiveBugReport>(*BT, llvm::StringRef(os.str()), errorNode);
0072         PSBR->addRange(CE->getSourceRange());
0073         if (!m_exception.reportConstCastAway(*PSBR, C))
0074           return;
0075         C.emitReport(std::move(PSBR));
0076         if (cname.empty())
0077           return;
0078         std::string tname = "constcastaway-checker.txt.unsorted";
0079         std::string tolog = "flagged class '" + cname + "' const qualifier cast away";
0080         support::writeLog(tolog, tname);
0081       }
0082     }
0083   }
0084 
0085 }  // namespace clangcms