/***************************************************Project Mutator****************************************************/ //-*-c++-*- /*first line intentionally left blank.*/ /*the source code for SaferCPP's automatic refactoring of C/C++ arrays.*/ /*Copyright (C) 2017 Noah L.,Farzad Sadeghi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.*/ /*code structure inspired by Eli Bendersky's tutorial on Rewriters.*/ /**********************************************************************************************************************/ /**********************************************************************************************************************/ /*included modules*/ /*Project Headers*/ #include "safercpp-arr.h" #include "../mutator_aux.h" /*Standard headers*/ #include #include #include #include #include #include #include /*Clang Headers*/ #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "clang/Rewrite/Core/Rewriter.h" /*LLVM Headers*/ #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Function.h" /**********************************************************************************************************************/ /*used namespaces*/ using namespace llvm; using namespace clang; using namespace clang::ast_matchers; using namespace clang::driver; using namespace clang::tooling; /**********************************************************************************************************************/ static llvm::cl::OptionCategory MatcherSampleCategory("TBD"); cl::opt CheckSystemHeader("SysHeader", cl::desc("safercpp will run through System Headers"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore); cl::opt MainFileOnly("MainOnly", cl::desc("safercpp will only report the results that reside in the main file"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore); cl::opt SafeSubset("SafeSubset", cl::desc("safercpp will check for elements outside of the (memory) safe subset of the language"), cl::init(true), cl::cat(MatcherSampleCategory), cl::ZeroOrMore); cl::opt ConvertToSCPP("ConvertToSCPP", cl::desc("safercpp will translate the source to a (memory) safe subset of the language"), cl::init(false), cl::cat(MatcherSampleCategory), cl::ZeroOrMore); /**********************************************************************************************************************/ SourceRange nice_source_range(const SourceRange& sr, Rewriter &Rewrite) { SourceLocation SL = sr.getBegin(); SourceLocation SLE = sr.getEnd(); if (SL.isMacroID() || SLE.isMacroID()) { int q = 5; } SL = Devi::SourceLocationHasMacro(SL, Rewrite, "start"); SLE = Devi::SourceLocationHasMacro(SLE, Rewrite, "end"); return SourceRange(SL, SLE); } bool filtered_out_by_location(const ast_matchers::MatchFinder::MatchResult &MR, SourceLocation SL) { bool retval = false; if (Devi::IsTheMatchInSysHeader(CheckSystemHeader, MR, SL)) { retval = true; } else if (!Devi::IsTheMatchInMainFile(MainFileOnly, MR, SL)) { retval = true; } return retval; } static std::string with_whitespace_removed(const std::string& str) { std::string retval = str; retval.erase(std::remove_if(retval.begin(), retval.end(), isspace), retval.end()); return retval; } static std::string with_newlines_removed(const std::string& str) { std::string retval = str; auto riter1 = retval.rbegin(); while (retval.rend() != riter1) { if ('\n' == *riter1) { auto riter2 = riter1; riter2++; retval.erase(riter1.base()--); while (retval.rend() != riter2) { /* look for and remove 'continued on the next line' backslash if present. */ if ('\\' == (*riter2)) { riter1++; retval.erase(riter2.base()--); break; } else if (!std::isspace(*riter2)) { break; } riter2++; } } riter1++; } return retval; } static std::vector f_declared_object_strings(const std::string& decl_stmt_str) { std::vector retval; auto nice_decl_stmt_str = with_newlines_removed(decl_stmt_str); auto semicolon_position = std::string::npos; for (size_t pos = 3; pos < nice_decl_stmt_str.size(); pos += 1) { if (';' == nice_decl_stmt_str[pos]) { semicolon_position = pos; } } if (std::string::npos == semicolon_position) { assert(false); return retval; } std::vector delimiter_positions; for (size_t pos = 3; ((pos < nice_decl_stmt_str.size()) && (pos < semicolon_position)); pos += 1) { if (',' == nice_decl_stmt_str[pos]) { delimiter_positions.push_back(pos); } } delimiter_positions.push_back(semicolon_position); auto first_delimiter_pos = delimiter_positions[0]; { auto pos1 = first_delimiter_pos - 1; auto pos2 = pos1; bool nonspace_found = false; while ((2 <= pos1) && (!nonspace_found)) { if (!std::isspace(nice_decl_stmt_str[pos1])) { pos2 = pos1 + 1; nonspace_found = true; } pos1 -= 1; } if (!nonspace_found) { assert(false); return retval; } bool space_found = false; while ((1 <= pos1) && (!space_found)) { if (std::isspace(nice_decl_stmt_str[pos1])) { space_found = true; } pos1 -= 1; } if (!space_found) { assert(false); return retval; } pos1 += 2; std::string first_declaration_string = nice_decl_stmt_str.substr(pos1, pos2 - pos1); retval.push_back(first_declaration_string); } { size_t delimiter_index = 0; while (delimiter_positions.size() > (delimiter_index + 1)) { if (!(delimiter_positions[delimiter_index] + 1 < delimiter_positions[(delimiter_index + 1)])) { //assert(false); } else { std::string declaration_string = nice_decl_stmt_str.substr(delimiter_positions[delimiter_index] + 1, delimiter_positions[(delimiter_index + 1)] - (delimiter_positions[delimiter_index] + 1)); retval.push_back(declaration_string); } delimiter_index += 1; } } return retval; } class CDeclReplacementActionRecord { public: CDeclReplacementActionRecord(Rewriter &Rewrite, const clang::DeclaratorDecl& ddecl, const std::string& replacement_text , const std::string& action_species) : m_Rewrite_ptr(&Rewrite), m_ddecl_cptr(&ddecl), m_replacement_text(replacement_text), m_action_species(action_species) { } virtual ~CDeclReplacementActionRecord() {} clang::SourceRange source_range() { clang::SourceRange retval = m_ddecl_cptr->getSourceRange(); return retval; } clang::SourceLocation start_location() { clang::SourceLocation retval = source_range().getBegin(); return retval; } std::string get_var_name() { std::string retval = m_ddecl_cptr->getNameAsString(); return retval; } const clang::DeclaratorDecl* get_ddecl_cptr() { return m_ddecl_cptr; } std::string replacement_text() { return m_replacement_text; } std::string action_species() { return m_action_species; } Rewriter* m_Rewrite_ptr = nullptr; const clang::DeclaratorDecl* m_ddecl_cptr = nullptr; std::string m_replacement_text; std::string m_action_species; }; class CDeclReplacementActionRecordsLog : public std::vector { public: CDeclReplacementActionRecordsLog::iterator find(const clang::DeclaratorDecl* ddecl_cptr) { CDeclReplacementActionRecordsLog::iterator retval = (*this).end(); CDeclReplacementActionRecordsLog::iterator iter = (*this).begin(); for (CDeclReplacementActionRecordsLog::iterator iter = (*this).begin(); (*this).end() != iter; iter++) { if ((*iter).get_ddecl_cptr() == ddecl_cptr) { retval = iter; break; } } return retval; } CDeclReplacementActionRecordsLog::iterator find(const clang::SourceLocation& start_location) { CDeclReplacementActionRecordsLog::iterator retval = (*this).end(); for (CDeclReplacementActionRecordsLog::iterator iter = (*this).begin(); (*this).end() != iter; iter++) { auto l_sl = (*iter).start_location(); if ((start_location.isValid()) && (l_sl.isValid()) && (start_location == l_sl)) { retval = iter; break; } } return retval; } }; class CReplacementAction { public: virtual ~CReplacementAction() {} virtual void do_replacement() const = 0; }; class CDDeclReplacementAction : public CReplacementAction { public: CDDeclReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const clang::DeclaratorDecl& ddecl) : m_Rewrite(Rewrite), m_MR(MR), m_ddecl_cptr(&ddecl) { } virtual ~CDDeclReplacementAction() {} virtual void do_replacement() const = 0; virtual const clang::DeclaratorDecl* get_ddecl_cptr() const { return m_ddecl_cptr; } clang::SourceRange source_range() { clang::SourceRange retval = m_ddecl_cptr->getSourceRange(); return retval; } clang::SourceLocation start_location() { clang::SourceLocation retval = source_range().getBegin(); return retval; } std::string get_var_name() { std::string retval = m_ddecl_cptr->getNameAsString(); return retval; } Rewriter& m_Rewrite; const MatchFinder::MatchResult m_MR; const clang::DeclaratorDecl* m_ddecl_cptr = nullptr; }; class CDynamicArrayReplacementAction : public CDDeclReplacementAction { public: using CDDeclReplacementAction::CDDeclReplacementAction; virtual ~CDynamicArrayReplacementAction() {} }; class CSetArrayPointerToNullReplacementAction : public CDynamicArrayReplacementAction { public: CSetArrayPointerToNullReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const clang::DeclaratorDecl& ddecl, const BinaryOperator* BO, const DeclRefExpr* DRE, const MemberExpr* ME) : CDynamicArrayReplacementAction(Rewrite, MR, ddecl), m_BO(BO), m_DRE(DRE), m_ME(ME) { } virtual ~CSetArrayPointerToNullReplacementAction() {} virtual void do_replacement() const { Rewriter &Rewrite = m_Rewrite; const MatchFinder::MatchResult &MR = m_MR; const BinaryOperator* BO = m_BO; const Expr* RHS = nullptr; const Expr* LHS = nullptr; if (BO != nullptr) { RHS = BO->getRHS(); LHS = BO->getLHS(); } const DeclRefExpr* DRE = m_DRE; const MemberExpr* ME = m_ME; if ((BO != nullptr) && (RHS != nullptr) && (LHS != nullptr) && (DRE != nullptr)) { auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite); SourceLocation BOSL = BOSR.getBegin(); SourceLocation BOSLE = BOSR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FBOSL = ASTC->getFullLoc(BOSL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = BOSL.printToString(*MR.SourceManager); std::string source_text; if (BOSL.isValid() && BOSLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(BOSL, BOSLE)); } else { return; } if (filtered_out_by_location(MR, BOSL)) { return void(); } Expr::NullPointerConstantKind kind = RHS->isNullPointerConstant(*ASTC, Expr::NullPointerConstantValueDependence()); if (clang::Expr::NPCK_NotNull != kind) { auto lhs_source_range = nice_source_range(LHS->getSourceRange(), Rewrite); std::string lhs_source_text; if (lhs_source_range.isValid()) { lhs_source_text = Rewrite.getRewrittenText(lhs_source_range); //auto lhs_source_text_sans_ws = with_whitespace_removed(lhs_source_text); QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string variable_name; std::string bo_replacement_code; const clang::DeclaratorDecl* DD = nullptr; auto decl = DRE->getDecl(); auto VD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; auto field_decl_source_range = nice_source_range(FD->getSourceRange(), Rewrite); auto field_decl_source_location_str = field_decl_source_range.getBegin().printToString(*MR.SourceManager); std::string field_decl_source_text; if (field_decl_source_range.isValid()) { field_decl_source_text = Rewrite.getRewrittenText(field_decl_source_range); decl_source_range = field_decl_source_range; } else { return; } QT = FD->getType(); variable_name = FD->getNameAsString(); } else if (nullptr != VD) { DD = VD; auto decl_source_range = nice_source_range(VD->getSourceRange(), Rewrite); auto qualified_name = VD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } QT = VD->getType(); variable_name = VD->getNameAsString(); } else { int q = 7; } if (nullptr != DD) { if (true) { if (true) { bo_replacement_code = lhs_source_text; bo_replacement_code += ".resize(0)"; auto BOSR = clang::SourceRange(BOSL, BOSLE); if (ConvertToSCPP && (BOSR.isValid())) { auto res2 = Rewrite.ReplaceText(BOSR, bo_replacement_code); int q = 3; } else { int q = 7; } } else { int q = 5; } } } int q = 5; } else { int q = 5; } int q = 5; } } } const BinaryOperator* m_BO; const DeclRefExpr* m_DRE; const MemberExpr* m_ME; }; std::string tolowerstr(const std::string& a) { std::string retval; for (const auto& ch : a) { retval += tolower(ch); } return retval; } class CFreeDynamicArrayReplacementAction : public CDynamicArrayReplacementAction { public: CFreeDynamicArrayReplacementAction(Rewriter &Rewrite, const MatchFinder::MatchResult &MR, const clang::DeclaratorDecl& ddecl, const CallExpr* CE, const DeclRefExpr* DRE, const MemberExpr* ME) : CDynamicArrayReplacementAction(Rewrite, MR, ddecl), m_CE(CE), m_DRE(DRE), m_ME(ME) { } virtual ~CFreeDynamicArrayReplacementAction() {} virtual void do_replacement() const { Rewriter &Rewrite = m_Rewrite; const MatchFinder::MatchResult &MR = m_MR; const CallExpr* CE = m_CE; const DeclRefExpr* DRE = m_DRE; const MemberExpr* ME = m_ME; if ((CE != nullptr) && (DRE != nullptr)) { auto CESR = nice_source_range(CE->getSourceRange(), Rewrite); SourceLocation CESL = CESR.getBegin(); SourceLocation CESLE = CESR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FCESL = ASTC->getFullLoc(CESL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = CESL.printToString(*MR.SourceManager); std::string source_text; if (CESL.isValid() && CESLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(CESL, CESLE)); } else { return; } if (filtered_out_by_location(MR, CESL)) { return void(); } auto function_decl = CE->getDirectCallee(); auto num_args = CE->getNumArgs(); if (function_decl && (1 == num_args)) { { std::string function_name = function_decl->getNameAsString(); static const std::string free_str = "free"; auto lc_function_name = tolowerstr(function_name); bool ends_with_free = ((lc_function_name.size() >= free_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - free_str.size(), free_str.size(), free_str))); if (ends_with_free) { auto iter = CE->arg_begin(); assert((*iter)->getType().getTypePtrOrNull()); auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite); std::string arg_source_text; if (arg_source_range.isValid()) { arg_source_text = Rewrite.getRewrittenText(arg_source_range); //auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text); QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string variable_name; std::string ce_replacement_code; const clang::DeclaratorDecl* DD = nullptr; auto decl = DRE->getDecl(); DD = dynamic_cast(decl); auto VD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; } else if (nullptr != VD) { DD = VD; } else { int q = 7; } if (nullptr != DD) { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } if (true) { ce_replacement_code = arg_source_text; ce_replacement_code += ".resize(0)"; auto CESR = clang::SourceRange(CESL, CESLE); if (ConvertToSCPP && (CESR.isValid())) { auto res2 = Rewrite.ReplaceText(CESR, ce_replacement_code); int q = 3; } else { int q = 7; } } } int q = 5; } else { int q = 5; } int q = 5; } } } } } const CallExpr* m_CE; const DeclRefExpr* m_DRE; const MemberExpr* m_ME; }; class CDynamicArrayReplacementActionMap : public std::multimap> { public: typedef std::multimap> base_class; iterator insert( const std::shared_ptr& cr_shptr ) { iterator retval(end()); if (!cr_shptr) { assert(false); } else { value_type val((*cr_shptr).get_ddecl_cptr(), cr_shptr); retval = base_class::insert(val); } return retval; } void do_and_dispose_matching_replacements(const clang::DeclaratorDecl& ddecl) { auto DD = &ddecl; auto range = base_class::equal_range(DD); while (range.first != range.second) { for (auto iter = range.first; range.second != iter; iter++) { (*((*iter).second)).do_replacement(); } base_class::erase(range.first, range.second); range = base_class::equal_range(DD); } } }; class CState1 { public: CDeclReplacementActionRecordsLog m_decl_replacement_action_records_log; CDynamicArrayReplacementActionMap m_dynamic_array_contingent_replacement_map; }; /**********************************************************************************************************************/ class MCSSSArrayToPointerDecay : public MatchFinder::MatchCallback { public: MCSSSArrayToPointerDecay (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { if (/*SafeSubset && */(MR.Nodes.getNodeAs("mcsssarraytopointerdecay") != nullptr)) { const CastExpr* CE = MR.Nodes.getNodeAs("mcsssarraytopointerdecay"); auto SR = nice_source_range(CE->getSourceRange(), Rewrite); SourceLocation SL = SR.getBegin(); SourceLocation SLE = SR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FSL = ASTC->getFullLoc(SL); auto source_location_str = SL.printToString(*MR.SourceManager); std::string source_text; if (SL.isValid() && SLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE)); } else { return; } if (filtered_out_by_location(MR, SL)) { /*intentionally left blank*/ } else { { if (false) { std::cout << "sss1.2:" << "array to pointer decay:"; std::cout << SL.printToString(*MR.SourceManager) << ":" << std::endl; //XMLDocOut.XMLAddNode(MR.Context, SL, "sss1.2", "array to pointer decay: "); //JSONDocOUT.JSONAddElement(MR.Context, SL, "sss1.2", "array to pointer decay: "); } } } } } private: Rewriter &Rewrite; CState1& m_state1; }; /**********************************************************************************************************************/ class MCSSSNativePointer : public MatchFinder::MatchCallback { public: MCSSSNativePointer (Rewriter &Rewrite) : Rewrite(Rewrite) {} virtual void run(const MatchFinder::MatchResult &MR) { if (SafeSubset && (MR.Nodes.getNodeAs("mcsssnativepointer") != nullptr)) { const VarDecl *VD = MR.Nodes.getNodeAs("mcsssnativepointer"); auto SR = nice_source_range(VD->getSourceRange(), Rewrite); SourceLocation SL = SR.getBegin(); SourceLocation SLE = SR.getEnd(); ASTContext* const ASTC = MR.Context; FullSourceLoc FSL = ASTC->getFullLoc(SL); auto source_location_str = SL.printToString(*MR.SourceManager); std::string source_text; if (SL.isValid() && SLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE)); } else { return; } if (filtered_out_by_location(MR, SL)) { /*intentionally left blank*/ } else { { if (false && SafeSubset) { std::cout << "sss1.1:" << "native pointer:"; std::cout << SL.printToString(*MR.SourceManager) << ":" << std::endl; //XMLDocOut.XMLAddNode(MR.Context, SL, "sss1.1", "native pointer: "); //JSONDocOUT.JSONAddElement(MR.Context, SL, "sss1.1", "native pointer: "); } } } } } virtual void onEndOfTranslationUnit() { } private: Rewriter &Rewrite; }; /**********************************************************************************************************************/ class MCSSSVarDecl : public MatchFinder::MatchCallback { public: MCSSSVarDecl (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { if ((MR.Nodes.getNodeAs("mcsssvardecl") != nullptr)) { const VarDecl* VD = MR.Nodes.getNodeAs("mcsssvardecl"); auto SR = nice_source_range(VD->getSourceRange(), Rewrite); SourceLocation SL = SR.getBegin(); SourceLocation SLE = SR.getEnd(); QualType QT = VD->getType(); const clang::Type* TP = QT.getTypePtr(); ASTContext *const ASTC = MR.Context; FullSourceLoc FSL = ASTC->getFullLoc(SL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = SL.printToString(*MR.SourceManager); std::string source_text; if (SL.isValid() && SLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE)); } else { return; } if (filtered_out_by_location(MR, SL)) { return void(); } auto storage_duration = VD->getStorageDuration(); bool has_dynamic_storage_duration = (clang::StorageDuration::SD_Dynamic == storage_duration); bool is_a_temporary = (clang::StorageDuration::SD_FullExpression == storage_duration); bool is_static = (clang::StorageDuration::SD_Static == storage_duration); bool is_a_function_parameter = (VD->isLocalVarDeclOrParm() && (!VD->isLocalVarDecl())); auto variable_name = VD->getName(); auto variable_name2 = VD->getNameAsString(); std::string identifier_name_str; auto pIdentifier = VD->getIdentifier(); if (pIdentifier) { identifier_name_str = pIdentifier->getName(); } std::string initialization_expr_str; auto pInitExpr = VD->getInit(); if (VD->hasInit() && pInitExpr) { auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite); initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range); } if (TP->isArrayType()) { auto ATP = static_cast(TP); auto element_type = ATP->getElementType(); auto elementSplitQualType = element_type.split(); auto element_type_str = clang::QualType::getAsString(elementSplitQualType); std::string replacement_code; if (is_static) { replacement_code += "static "; } replacement_code += "mse::mstd::array<"; replacement_code += element_type_str; replacement_code += ", "; if (TP->isConstantArrayType()) { auto CATP = static_cast(TP); if (!CATP) { assert(false); } else { auto array_size = CATP->getSize(); auto left_bracket_pos = source_text.find('['); auto right_bracket_pos = source_text.find(']'); if ((std::string::npos != left_bracket_pos) && (std::string::npos != right_bracket_pos) && (left_bracket_pos + 1 < right_bracket_pos)) { auto array_size_expression_text = source_text.substr(left_bracket_pos + 1, right_bracket_pos - (left_bracket_pos + 1)); replacement_code += array_size_expression_text; int q = 3; } else { int q = 7; } int q = 5; } } else if (TP->isVariableArrayType()) { auto VATP = static_cast(TP); if (!VATP) { assert(false); } else { auto size_expr = VATP->getSizeExpr(); } } replacement_code += "> "; std::string new_array_variable_name = variable_name; new_array_variable_name += "_array"; replacement_code += new_array_variable_name; if ("" != initialization_expr_str) { replacement_code += " = "; replacement_code += initialization_expr_str; } replacement_code += "; \n"; if (is_static) { replacement_code += "static "; } replacement_code += "auto "; replacement_code += variable_name; replacement_code += " = "; replacement_code += new_array_variable_name; replacement_code += ".begin()"; if (ConvertToSCPP && SL.isValid() && SLE.isValid()) { auto res = Rewrite.ReplaceText(SourceRange(SL, SLE), replacement_code); CDeclReplacementActionRecord action_record(Rewrite, *VD, replacement_code, "native to mse array"); m_state1.m_decl_replacement_action_records_log.push_back(action_record); m_state1.m_dynamic_array_contingent_replacement_map.do_and_dispose_matching_replacements(*VD); int q = 3; } else { int q = 7; } m_state1.m_dynamic_array_contingent_replacement_map.do_and_dispose_matching_replacements(*VD); int q = 5; } else { ; } } } virtual void onEndOfTranslationUnit() { } private: Rewriter &Rewrite; CState1& m_state1; }; /**********************************************************************************************************************/ class CRandomAccessIteratorFromPointerDDeclRetval { public: std::string m_replacement_code; std::string m_action_species; }; static CRandomAccessIteratorFromPointerDDeclRetval RandomAccessIteratorFromPointerDDecl(const DeclaratorDecl* DD, Rewriter &Rewrite) { CRandomAccessIteratorFromPointerDDeclRetval retval; QualType QT = DD->getType(); const clang::Type* TP = QT.getTypePtr(); clang::StorageDuration storage_duration = clang::StorageDuration::SD_Automatic; bool has_dynamic_storage_duration = false; bool is_a_temporary = false; bool is_static = false; bool is_a_function_parameter = false; std::string initialization_expr_str; auto VD = dynamic_cast(DD); if (VD) { storage_duration = VD->getStorageDuration(); has_dynamic_storage_duration = (clang::StorageDuration::SD_Dynamic == storage_duration); is_a_temporary = (clang::StorageDuration::SD_FullExpression == storage_duration); is_static = (clang::StorageDuration::SD_Static == storage_duration); is_a_function_parameter = (VD->isLocalVarDeclOrParm() && (!VD->isLocalVarDecl())); auto pInitExpr = VD->getInit(); if (VD->hasInit() && pInitExpr) { auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite); initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range); } } auto variable_name = DD->getNameAsString(); std::string identifier_name_str; auto pIdentifier = DD->getIdentifier(); if (pIdentifier) { identifier_name_str = pIdentifier->getName(); } bool replacement_code_generated = false; if (TP->isPointerType()) { auto TPP = static_cast(TP); if (TPP) { auto target_type = TPP->getPointeeType(); auto splitQualType = target_type.split(); auto type_str = clang::QualType::getAsString(splitQualType); if (("char" != type_str) && ("const char" != type_str)) { std::string replacement_code; if (is_static) { replacement_code += "static "; } replacement_code += "mse::TNullableAnyRandomAccessIterator<"; replacement_code += type_str; replacement_code += "> "; replacement_code += variable_name; if ("" != initialization_expr_str) { replacement_code += " = "; replacement_code += initialization_expr_str; } retval.m_replacement_code = replacement_code; retval.m_action_species = "pointer to random access iterator"; replacement_code_generated = true; } else { int q = 3; } } else { assert(false); int q = 1; } } if (!replacement_code_generated) { auto splitQualType = QT.split(); auto type_str = clang::QualType::getAsString(splitQualType); std::string replacement_code; if (is_static) { replacement_code += "static "; } replacement_code += type_str; replacement_code += " "; replacement_code += variable_name; if ("" != initialization_expr_str) { replacement_code += " = "; replacement_code += initialization_expr_str; } retval.m_replacement_code = replacement_code; retval.m_action_species = "char*"; replacement_code_generated = true; } return retval; } static std::vector IndividualDeclaratorDecls(const DeclaratorDecl* VD, Rewriter &Rewrite) { std::vector retval; if (!VD) { assert(false); return retval; } auto SR = nice_source_range(VD->getSourceRange(), Rewrite); SourceLocation SL = SR.getBegin(); auto decl_context = VD->getDeclContext(); if ((!decl_context) || (!SL.isValid())) { assert(false); retval.push_back(VD); } else { for (auto decl_iter = decl_context->decls_begin(); decl_iter != decl_context->decls_end(); decl_iter++) { auto decl = (*decl_iter); auto var_decl = dynamic_cast(decl); if (var_decl) { auto VDSR = nice_source_range(var_decl->getSourceRange(), Rewrite); SourceLocation l_SL = VDSR.getBegin(); if (l_SL == SL) { retval.push_back(var_decl); } } } } if (0 == retval.size()) { assert(false); } return retval; } class MCSSSPointerArithmetic : public MatchFinder::MatchCallback { public: MCSSSPointerArithmetic (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { const DeclRefExpr* DRE = MR.Nodes.getNodeAs("mcssspointerarithmetic"); const MemberExpr* ME = MR.Nodes.getNodeAs("mcssspointerarithmetic2"); if (DRE != nullptr) { const DeclRefExpr* DRE = MR.Nodes.getNodeAs("mcssspointerarithmetic"); auto SR = nice_source_range(DRE->getSourceRange(), Rewrite); SourceLocation SL = SR.getBegin(); SourceLocation SLE = SR.getEnd(); QualType QT = DRE->getType(); const clang::Type* TP = QT.getTypePtr(); ASTContext *const ASTC = MR.Context; FullSourceLoc FSL = ASTC->getFullLoc(SL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = SL.printToString(*MR.SourceManager); std::string source_text; if (SL.isValid() && SLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(SL, SLE)); } else { return; } if (filtered_out_by_location(MR, SL)) { return void(); } auto decl = DRE->getDecl(); auto DD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; } if (!DD) { return; } else { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); std::string variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } auto iter = m_state1.m_decl_replacement_action_records_log.find(DD); if (m_state1.m_decl_replacement_action_records_log.end() != iter) { /* This variable declaration has already been processed. Probably. */ return; } auto var_decls = IndividualDeclaratorDecls(DD, Rewrite); if ((1 <= var_decls.size()) && (var_decls.back() == DD)) { std::vector action_species_list; std::string replacement_code; for (const auto& var_decl : var_decls) { auto res = RandomAccessIteratorFromPointerDDecl(var_decl, Rewrite); action_species_list.push_back(res.m_action_species); replacement_code += res.m_replacement_code; replacement_code += "; \n"; } if (replacement_code.size() >= 3) { replacement_code = replacement_code.substr(0, replacement_code.size() - 3); } if (ConvertToSCPP && decl_source_range.isValid() && (3 <= replacement_code.size())) { auto res = Rewrite.ReplaceText(decl_source_range, replacement_code); for (auto var_decl : var_decls) { assert(1 <= action_species_list.size()); CDeclReplacementActionRecord action_record(Rewrite, *var_decl, replacement_code, action_species_list.front()); action_species_list.erase(action_species_list.begin()); m_state1.m_decl_replacement_action_records_log.push_back(action_record); //m_state1.m_dynamic_array_contingent_replacement_map.do_and_dispose_matching_replacements(*var_decl); } int q = 3; } else { int q = 7; } } else { int q = 7; } } } } private: Rewriter &Rewrite; CState1& m_state1; }; /**********************************************************************************************************************/ static std::string IPointerFromPointerDecl(const DeclaratorDecl* DD, Rewriter &Rewrite) { std::string retval; QualType QT = DD->getType(); const clang::Type* TP = QT.getTypePtr(); clang::StorageDuration storage_duration = clang::StorageDuration::SD_Automatic; bool has_dynamic_storage_duration = false; bool is_a_temporary = false; bool is_static = false; bool is_a_function_parameter = false; std::string initialization_expr_str; auto FD = dynamic_cast(DD); auto VD = dynamic_cast(DD); if (VD) { storage_duration = VD->getStorageDuration(); has_dynamic_storage_duration = (clang::StorageDuration::SD_Dynamic == storage_duration); is_a_temporary = (clang::StorageDuration::SD_FullExpression == storage_duration); is_static = (clang::StorageDuration::SD_Static == storage_duration); is_a_function_parameter = (VD->isLocalVarDeclOrParm() && (!VD->isLocalVarDecl())); auto pInitExpr = VD->getInit(); if (VD->hasInit() && pInitExpr) { auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite); initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range); } } else if (FD) { /* Just placeholder code for now. Haven't thought about this case yet. */ auto pInitExpr = FD->getInClassInitializer(); if (FD->hasInClassInitializer() && pInitExpr) { auto init_expr_source_range = nice_source_range(pInitExpr->getSourceRange(), Rewrite); initialization_expr_str = Rewrite.getRewrittenText(init_expr_source_range); } } auto variable_name = DD->getNameAsString(); std::string identifier_name_str; auto pIdentifier = DD->getIdentifier(); if (pIdentifier) { identifier_name_str = pIdentifier->getName(); } bool replacement_code_generated = false; if (TP->isPointerType()) { auto TPP = static_cast(TP); if (TPP) { auto target_type = TPP->getPointeeType(); auto splitQualType = target_type.split(); auto type_str = clang::QualType::getAsString(splitQualType); if (("char" != type_str) && ("const char" != type_str)) { std::string replacement_code; if (is_static) { replacement_code += "static "; } replacement_code += "mse::TIPointerWithBundledVector<"; replacement_code += type_str; replacement_code += "> "; replacement_code += variable_name; if (("" != initialization_expr_str) && false) { replacement_code += " = "; replacement_code += initialization_expr_str; } retval = replacement_code; replacement_code_generated = true; } else { int q = 3; } } else { assert(false); int q = 1; } } if (!replacement_code_generated) { auto splitQualType = QT.split(); auto type_str = clang::QualType::getAsString(splitQualType); std::string replacement_code; if (is_static) { replacement_code += "static "; } replacement_code += type_str; replacement_code += " "; replacement_code += variable_name; if ("" != initialization_expr_str) { replacement_code += " = "; replacement_code += initialization_expr_str; } retval = replacement_code; replacement_code_generated = true; } return retval; } class MCSSSMalloc : public MatchFinder::MatchCallback { public: MCSSSMalloc (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { const BinaryOperator* BO = MR.Nodes.getNodeAs("mcsssmalloc1"); const CallExpr* CE = MR.Nodes.getNodeAs("mcsssmalloc2"); const DeclRefExpr* DRE = MR.Nodes.getNodeAs("mcsssmalloc3"); const MemberExpr* ME = MR.Nodes.getNodeAs("mcsssmalloc4"); if ((BO != nullptr) && (CE != nullptr) && (DRE != nullptr)) { auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite); SourceLocation BOSL = BOSR.getBegin(); SourceLocation BOSLE = BOSR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FBOSL = ASTC->getFullLoc(BOSL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = BOSL.printToString(*MR.SourceManager); std::string source_text; if (BOSL.isValid() && BOSLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(BOSL, BOSLE)); } else { return; } if (filtered_out_by_location(MR, BOSL)) { return void(); } auto function_decl = CE->getDirectCallee(); auto num_args = CE->getNumArgs(); if (function_decl && ((1 == num_args) || (2 == num_args))) { std::string function_name = function_decl->getNameAsString(); static const std::string alloc_str = "alloc"; static const std::string realloc_str = "realloc"; auto lc_function_name = tolowerstr(function_name); bool ends_with_alloc = ((lc_function_name.size() >= alloc_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - alloc_str.size(), alloc_str.size(), alloc_str))); bool ends_with_realloc = (ends_with_alloc && (lc_function_name.size() >= realloc_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - realloc_str.size(), realloc_str.size(), realloc_str))); bool still_potentially_valid1 = (ends_with_alloc && (1 == num_args)) || (ends_with_realloc && (2 == num_args)); if (still_potentially_valid1) { auto iter = CE->arg_begin(); if (ends_with_realloc) { iter++; } { auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite); std::string arg_source_text; if (arg_source_range.isValid()) { arg_source_text = Rewrite.getRewrittenText(arg_source_range); //auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text); auto sizeof_start_index = arg_source_text.find("sizeof("); if (std::string::npos != sizeof_start_index) { auto sizeof_end_index = arg_source_text.find(")", sizeof_start_index); if (std::string::npos != sizeof_end_index) { assert(sizeof_end_index > sizeof_start_index); std::string before_str = arg_source_text.substr(0, sizeof_start_index); std::string after_str; if (sizeof_end_index + 1 < arg_source_text.size()) { after_str = arg_source_text.substr(sizeof_end_index + 1); } bool asterisk_found = false; auto index = before_str.size() - 1; while (0 <= index) { if ('*' == before_str[index]) { asterisk_found = true; } if (!std::isspace(before_str[index])) { break; } index -= 1; } if (asterisk_found) { before_str = before_str.substr(0, index); } else { size_t index2 = 0; while (after_str.size() > index2) { if ('*' == after_str[index2]) { asterisk_found = true; } if (!std::isspace(after_str[index2])) { break; } index2 += 1; } if (asterisk_found) { after_str = after_str.substr(index2 + 1); } } if (asterisk_found) { /* The argument is in the form "something * sizeof(something_else)" or * "sizeof(something) * something_else". So we're just going to assume that * this is an instance of an array being allocated. */ std::string num_elements_text = before_str + after_str; QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string declaration_replacement_code; std::string variable_name; std::string bo_replacement_code; const clang::DeclaratorDecl* DD = nullptr; auto decl = DRE->getDecl(); DD = dynamic_cast(decl); auto VD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; } else if (nullptr != VD) { DD = VD; } else { int q = 7; } if (nullptr != DD) { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } auto decls = IndividualDeclaratorDecls(DD, Rewrite); if ((1 <= decls.size()) && (decls.back() == DD)) { for (const auto& decl : decls) { declaration_replacement_code += IPointerFromPointerDecl(decl, Rewrite); declaration_replacement_code += "; \n"; } if (declaration_replacement_code.size() >= 3) { declaration_replacement_code = declaration_replacement_code.substr(0, declaration_replacement_code.size() - 3); } } else { int q = 7; } const clang::Type* TP = QT.getTypePtr(); if (TP->isArrayType()) { auto ATP = static_cast(TP); assert(nullptr != ATP); auto element_type = ATP->getElementType(); auto elementSplitQualType = element_type.split(); element_type_str = clang::QualType::getAsString(elementSplitQualType); } else if (TP->isPointerType()) { auto TPP = static_cast(TP); assert(nullptr != TPP); auto target_type = TPP->getPointeeType(); auto splitQualType = target_type.split(); auto type_str = clang::QualType::getAsString(splitQualType); if (("char" != type_str) && ("const char" != type_str)) { element_type_str = type_str; } } if ("" != element_type_str) { auto lhs = BO->getLHS(); auto lhs_source_range = nice_source_range(lhs->getSourceRange(), Rewrite); auto lhs_source_text = Rewrite.getRewrittenText(lhs_source_range); bo_replacement_code += lhs_source_text; bo_replacement_code += ".resize("; bo_replacement_code += num_elements_text; bo_replacement_code += ")"; auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } auto BOSR = clang::SourceRange(BOSL, BOSLE); if (ConvertToSCPP && decl_source_range.isValid() && (BOSR.isValid())) { if ((3 <= declaration_replacement_code.size())) { bool already_replaced_flag = false; size_t replacement_text_length = 0; for (const auto& decl : decls) { auto iter = m_state1.m_decl_replacement_action_records_log.find(decl); if (m_state1.m_decl_replacement_action_records_log.end() != iter) { /* This declaration had already been replaced. We'll need to "undo" * the replacement. */ already_replaced_flag = true; auto replacement_text = (*iter).replacement_text(); if ((*iter).replacement_text().size() > replacement_text_length) { replacement_text_length = (*iter).replacement_text().size(); } m_state1.m_decl_replacement_action_records_log.erase(iter); } CDeclReplacementActionRecord action_record(Rewrite, *decl, declaration_replacement_code, "pointer targeting heap allocated array to mse vector iterator"); m_state1.m_decl_replacement_action_records_log.push_back(action_record); m_state1.m_dynamic_array_contingent_replacement_map.do_and_dispose_matching_replacements(*decl); } auto adj_decl_source_range = decl_source_range; if (already_replaced_flag) { adj_decl_source_range = clang::SourceRange(decl_source_range.getBegin(), decl_source_range.getBegin().getLocWithOffset(replacement_text_length)); } auto adj_decl_source_text = Rewrite.getRewrittenText(adj_decl_source_range); auto res = Rewrite.ReplaceText(decl_source_range, declaration_replacement_code); } auto res2 = Rewrite.ReplaceText(BOSR, bo_replacement_code); int q = 3; } else { int q = 7; } } } int q = 5; } } } } else { int q = 5; } int q = 5; } } } } } private: Rewriter &Rewrite; CState1& m_state1; }; class MCSSSMallocInitializer : public MatchFinder::MatchCallback { public: MCSSSMallocInitializer (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { const DeclStmt* DS = MR.Nodes.getNodeAs("mcsssmallocinitializer1"); const CallExpr* CE = MR.Nodes.getNodeAs("mcsssmallocinitializer2"); const DeclaratorDecl* DD = MR.Nodes.getNodeAs("mcsssmallocinitializer3"); if ((DS != nullptr) && (CE != nullptr) && (DD != nullptr)) { auto DSSR = nice_source_range(DS->getSourceRange(), Rewrite); SourceLocation DSSL = DSSR.getBegin(); SourceLocation DSSLE = DSSR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FDSSL = ASTC->getFullLoc(DSSL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = DSSL.printToString(*MR.SourceManager); std::string source_text; if (DSSL.isValid() && DSSLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(DSSL, DSSLE)); } else { return; } if (filtered_out_by_location(MR, DSSL)) { return void(); } auto function_decl = CE->getDirectCallee(); auto num_args = CE->getNumArgs(); if (function_decl && ((1 == num_args) || (2 == num_args))) { std::string function_name = function_decl->getNameAsString(); static const std::string alloc_str = "alloc"; static const std::string realloc_str = "realloc"; auto lc_function_name = tolowerstr(function_name); bool ends_with_alloc = ((lc_function_name.size() >= alloc_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - alloc_str.size(), alloc_str.size(), alloc_str))); bool ends_with_realloc = (ends_with_alloc && (lc_function_name.size() >= realloc_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - realloc_str.size(), realloc_str.size(), realloc_str))); bool still_potentially_valid1 = (ends_with_alloc && (1 == num_args)) || (ends_with_realloc && (2 == num_args)); if (still_potentially_valid1) { auto iter = CE->arg_begin(); if (ends_with_realloc) { iter++; } { auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite); std::string arg_source_text; if (arg_source_range.isValid()) { arg_source_text = Rewrite.getRewrittenText(arg_source_range); //auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text); auto sizeof_start_index = arg_source_text.find("sizeof("); if (std::string::npos != sizeof_start_index) { auto sizeof_end_index = arg_source_text.find(")", sizeof_start_index); if (std::string::npos != sizeof_end_index) { assert(sizeof_end_index > sizeof_start_index); std::string before_str = arg_source_text.substr(0, sizeof_start_index); std::string after_str; if (sizeof_end_index + 1 < arg_source_text.size()) { after_str = arg_source_text.substr(sizeof_end_index + 1); } bool asterisk_found = false; auto index = before_str.size() - 1; while (0 <= index) { if ('*' == before_str[index]) { asterisk_found = true; } if (!std::isspace(before_str[index])) { break; } index -= 1; } if (asterisk_found) { before_str = before_str.substr(0, index); } else { size_t index2 = 0; while (after_str.size() > index2) { if ('*' == after_str[index2]) { asterisk_found = true; } if (!std::isspace(after_str[index2])) { break; } index2 += 1; } if (asterisk_found) { after_str = after_str.substr(index2 + 1); } } if (asterisk_found) { /* The argument is in the form "something * sizeof(something_else)" or * "sizeof(something) * something_else". So we're just going to assume that * this is an instance of an array being allocated. */ std::string num_elements_text = before_str + after_str; QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string declaration_replacement_code; std::string variable_name; if (nullptr != DD) { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } auto decls = IndividualDeclaratorDecls(DD, Rewrite); if ((1 <= decls.size()) && (decls.back() == DD)) { for (const auto& decl : decls) { declaration_replacement_code += IPointerFromPointerDecl(decl, Rewrite); declaration_replacement_code += "("; declaration_replacement_code += num_elements_text; declaration_replacement_code += "); \n"; } if (declaration_replacement_code.size() >= 3) { declaration_replacement_code = declaration_replacement_code.substr(0, declaration_replacement_code.size() - 3); } } else { int q = 7; } const clang::Type* TP = QT.getTypePtr(); if (TP->isArrayType()) { auto ATP = static_cast(TP); assert(nullptr != ATP); auto element_type = ATP->getElementType(); auto elementSplitQualType = element_type.split(); element_type_str = clang::QualType::getAsString(elementSplitQualType); } else if (TP->isPointerType()) { auto TPP = static_cast(TP); assert(nullptr != TPP); auto target_type = TPP->getPointeeType(); auto splitQualType = target_type.split(); auto type_str = clang::QualType::getAsString(splitQualType); if (("char" != type_str) && ("const char" != type_str)) { element_type_str = type_str; } } if ("" != element_type_str) { auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } auto DSSR = clang::SourceRange(DSSL, DSSLE); if (ConvertToSCPP && decl_source_range.isValid() && (DSSR.isValid())) { if ((3 <= declaration_replacement_code.size())) { bool already_replaced_flag = false; size_t replacement_text_length = 0; for (const auto& decl : decls) { auto iter = m_state1.m_decl_replacement_action_records_log.find(decl); if (m_state1.m_decl_replacement_action_records_log.end() != iter) { /* This declaration had already been replaced. We'll need to "undo" * the replacement. */ already_replaced_flag = true; if ((*iter).replacement_text().size() > replacement_text_length) { replacement_text_length = (*iter).replacement_text().size(); } m_state1.m_decl_replacement_action_records_log.erase(iter); } CDeclReplacementActionRecord action_record(Rewrite, *decl, declaration_replacement_code, "pointer targeting heap allocated array to mse vector iterator"); m_state1.m_decl_replacement_action_records_log.push_back(action_record); m_state1.m_dynamic_array_contingent_replacement_map.do_and_dispose_matching_replacements(*decl); } auto adj_decl_source_range = decl_source_range; if (already_replaced_flag) { adj_decl_source_range = clang::SourceRange(decl_source_range.getBegin(), decl_source_range.getBegin().getLocWithOffset(replacement_text_length)); } auto res = Rewrite.ReplaceText(decl_source_range, declaration_replacement_code); } int q = 3; } else { int q = 7; } } } int q = 5; } } } } else { int q = 5; } int q = 5; } } } } } private: Rewriter &Rewrite; CState1& m_state1; }; class MCSSSFree : public MatchFinder::MatchCallback { public: MCSSSFree (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { const CallExpr* CE = MR.Nodes.getNodeAs("mcsssfree1"); const DeclRefExpr* DRE = MR.Nodes.getNodeAs("mcsssfree2"); const MemberExpr* ME = MR.Nodes.getNodeAs("mcsssfree3"); if ((CE != nullptr) && (DRE != nullptr)) { auto CESR = nice_source_range(CE->getSourceRange(), Rewrite); SourceLocation CESL = CESR.getBegin(); SourceLocation CESLE = CESR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FCESL = ASTC->getFullLoc(CESL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = CESL.printToString(*MR.SourceManager); std::string source_text; if (CESL.isValid() && CESLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(CESL, CESLE)); } else { return; } if (filtered_out_by_location(MR, CESL)) { return void(); } auto function_decl = CE->getDirectCallee(); auto num_args = CE->getNumArgs(); if (function_decl && (1 == num_args)) { { std::string function_name = function_decl->getNameAsString(); static const std::string free_str = "free"; auto lc_function_name = tolowerstr(function_name); bool ends_with_free = ((lc_function_name.size() >= free_str.size()) && (0 == lc_function_name.compare(lc_function_name.size() - free_str.size(), free_str.size(), free_str))); if (ends_with_free) { auto iter = CE->arg_begin(); assert((*iter)->getType().getTypePtrOrNull()); auto arg_source_range = nice_source_range((*iter)->getSourceRange(), Rewrite); std::string arg_source_text; if (arg_source_range.isValid()) { arg_source_text = Rewrite.getRewrittenText(arg_source_range); //auto arg_source_text_sans_ws = with_whitespace_removed(arg_source_text); QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string variable_name; std::string ce_replacement_code; const clang::DeclaratorDecl* DD = nullptr; auto decl = DRE->getDecl(); DD = dynamic_cast(decl); auto VD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; } else if (nullptr != VD) { DD = VD; } else { int q = 7; } if (nullptr != DD) { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } auto iter = m_state1.m_decl_replacement_action_records_log.find(DD/*decl_source_range.getBegin()*/); if (m_state1.m_decl_replacement_action_records_log.end() != iter) { if ("pointer targeting heap allocated array to mse vector iterator" == (*iter).action_species()) { ce_replacement_code = arg_source_text; ce_replacement_code += ".resize(0)"; auto CESR = clang::SourceRange(CESL, CESLE); if (ConvertToSCPP && (CESR.isValid())) { auto res2 = Rewrite.ReplaceText(CESR, ce_replacement_code); int q = 3; } else { int q = 7; } } } else { auto cr_shptr = std::make_shared(Rewrite, MR, *DD, CE, DRE, ME); m_state1.m_dynamic_array_contingent_replacement_map.insert(cr_shptr); } } int q = 5; } else { int q = 5; } int q = 5; } } } } } private: Rewriter &Rewrite; CState1& m_state1; }; class MCSSSSetToNull : public MatchFinder::MatchCallback { public: MCSSSSetToNull (Rewriter &Rewrite, CState1& state1) : Rewrite(Rewrite), m_state1(state1) {} virtual void run(const MatchFinder::MatchResult &MR) { const BinaryOperator* BO = MR.Nodes.getNodeAs("mcssssettonull1"); const Expr* RHS = nullptr; const Expr* LHS = nullptr; if (BO != nullptr) { RHS = BO->getRHS(); LHS = BO->getLHS(); } const DeclRefExpr* DRE = MR.Nodes.getNodeAs("mcssssettonull3"); const MemberExpr* ME = MR.Nodes.getNodeAs("mcssssettonull4"); if ((BO != nullptr) && (RHS != nullptr) && (LHS != nullptr) && (DRE != nullptr)) { auto BOSR = nice_source_range(BO->getSourceRange(), Rewrite); SourceLocation BOSL = BOSR.getBegin(); SourceLocation BOSLE = BOSR.getEnd(); ASTContext *const ASTC = MR.Context; FullSourceLoc FBOSL = ASTC->getFullLoc(BOSL); SourceManager &SM = ASTC->getSourceManager(); auto source_location_str = BOSL.printToString(*MR.SourceManager); std::string source_text; if (BOSL.isValid() && BOSLE.isValid()) { source_text = Rewrite.getRewrittenText(SourceRange(BOSL, BOSLE)); } else { return; } if (filtered_out_by_location(MR, BOSL)) { return void(); } Expr::NullPointerConstantKind kind = RHS->isNullPointerConstant(*ASTC, Expr::NullPointerConstantValueDependence()); if (clang::Expr::NPCK_NotNull != kind) { auto lhs_source_range = nice_source_range(LHS->getSourceRange(), Rewrite); std::string lhs_source_text; if (lhs_source_range.isValid()) { lhs_source_text = Rewrite.getRewrittenText(lhs_source_range); //auto lhs_source_text_sans_ws = with_whitespace_removed(lhs_source_text); QualType QT; std::string element_type_str; clang::SourceRange decl_source_range; std::string variable_name; std::string bo_replacement_code; const clang::DeclaratorDecl* DD = nullptr; auto decl = DRE->getDecl(); DD = dynamic_cast(decl); auto VD = dynamic_cast(decl); const clang::FieldDecl* FD = nullptr; if (nullptr != ME) { auto member_decl = ME->getMemberDecl(); FD = dynamic_cast(ME->getMemberDecl()); } if (nullptr != FD) { DD = FD; } else if (nullptr != VD) { DD = VD; } else { int q = 7; } if (nullptr != DD) { auto decl_source_range = nice_source_range(DD->getSourceRange(), Rewrite); auto decl_source_location_str = decl_source_range.getBegin().printToString(*MR.SourceManager); std::string decl_source_text; if (decl_source_range.isValid()) { decl_source_text = Rewrite.getRewrittenText(decl_source_range); } else { return; } QT = DD->getType(); variable_name = DD->getNameAsString(); auto qualified_name = DD->getQualifiedNameAsString(); static const std::string mse_namespace_str1 = "mse::"; static const std::string mse_namespace_str2 = "::mse::"; if ((0 == qualified_name.compare(0, mse_namespace_str1.size(), mse_namespace_str1)) || (0 == qualified_name.compare(0, mse_namespace_str2.size(), mse_namespace_str2))) { return; } if ((DD->getType() == LHS->getType())) { auto iter = m_state1.m_decl_replacement_action_records_log.find(DD/*decl_source_range.getBegin()*/); if ((m_state1.m_decl_replacement_action_records_log.end() != iter) && ("pointer targeting heap allocated array to mse vector iterator" == (*iter).action_species()) && ((*iter).get_ddecl_cptr()->getType() == LHS->getType())) { if (true) { bo_replacement_code = lhs_source_text; bo_replacement_code += ".resize(0)"; auto BOSR = clang::SourceRange(BOSL, BOSLE); if (ConvertToSCPP && (BOSR.isValid())) { auto res2 = Rewrite.ReplaceText(BOSR, bo_replacement_code); int q = 3; } else { int q = 7; } } else { int q = 5; } } else { auto cr_shptr = std::make_shared(Rewrite, MR, *DD, BO, DRE, ME); m_state1.m_dynamic_array_contingent_replacement_map.insert(cr_shptr); } } } int q = 5; } else { int q = 5; } int q = 5; } } } private: Rewriter &Rewrite; CState1& m_state1; }; /**********************************************************************************************************************/ class MyASTConsumer : public ASTConsumer { public: MyASTConsumer(Rewriter &R) : HandlerForSSSNativePointer(R), HandlerForSSSArrayToPointerDecay(R, m_state1), \ HandlerForSSSVarDecl(R, m_state1), HandlerForSSSPointerArithmetic(R, m_state1), \ HandlerForSSSMalloc(R, m_state1), HandlerForSSSMallocInitializer(R, m_state1), \ HandlerForSSSFree(R, m_state1), HandlerForSSSSetToNull(R, m_state1) { Matcher.addMatcher(varDecl(hasType(pointerType())).bind("mcsssnativepointer"), &HandlerForSSSNativePointer); Matcher.addMatcher(castExpr(allOf(hasCastKind(CK_ArrayToPointerDecay), unless(hasParent(arraySubscriptExpr())))).bind("mcsssarraytopointerdecay"), &HandlerForSSSArrayToPointerDecay); Matcher.addMatcher(varDecl().bind("mcsssvardecl"), &HandlerForSSSVarDecl); Matcher.addMatcher(declRefExpr(allOf(hasParent(expr(anyOf( \ unaryOperator(hasOperatorName("++")), unaryOperator(hasOperatorName("--")), \ binaryOperator(hasOperatorName("+=")), binaryOperator(hasOperatorName("-=")), \ hasParent(expr(anyOf( \ binaryOperator(hasOperatorName("+")), binaryOperator(hasOperatorName("+=")), \ binaryOperator(hasOperatorName("-")), binaryOperator(hasOperatorName("-=")), \ binaryOperator(hasOperatorName("<=")), binaryOperator(hasOperatorName("<")), \ binaryOperator(hasOperatorName(">=")), binaryOperator(hasOperatorName(">")), \ arraySubscriptExpr(), clang::ast_matchers::castExpr(hasParent(arraySubscriptExpr())) \ )))))), to(declaratorDecl(hasType(pointerType()))))).bind("mcssspointerarithmetic"), &HandlerForSSSPointerArithmetic); Matcher.addMatcher(memberExpr(allOf(hasDescendant(declRefExpr().bind("mcssspointerarithmetic")), hasParent(expr(anyOf( \ unaryOperator(hasOperatorName("++")), unaryOperator(hasOperatorName("--")), \ binaryOperator(hasOperatorName("+=")), binaryOperator(hasOperatorName("-=")), \ hasParent(expr(anyOf( \ binaryOperator(hasOperatorName("+")), binaryOperator(hasOperatorName("+=")), \ binaryOperator(hasOperatorName("-")), binaryOperator(hasOperatorName("-=")), \ binaryOperator(hasOperatorName("<=")), binaryOperator(hasOperatorName("<")), \ binaryOperator(hasOperatorName(">=")), binaryOperator(hasOperatorName(">")), \ arraySubscriptExpr(), clang::ast_matchers::castExpr(hasParent(arraySubscriptExpr())) \ )))))), member(hasType(pointerType())))).bind("mcssspointerarithmetic2"), &HandlerForSSSPointerArithmetic); Matcher.addMatcher(binaryOperator(allOf( hasOperatorName("="), hasRHS( anyOf( cStyleCastExpr(has(callExpr().bind("mcsssmalloc2"))), callExpr().bind("mcsssmalloc2") ) ), hasLHS(anyOf( memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssmalloc3")))).bind("mcsssmalloc4"), hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssmalloc3")))).bind("mcsssmalloc4")), hasDescendant(declRefExpr().bind("mcsssmalloc3")), declRefExpr().bind("mcsssmalloc3") )), hasLHS(expr(hasType(pointerType()))) )).bind("mcsssmalloc1"), &HandlerForSSSMalloc); Matcher.addMatcher(declStmt(hasDescendant( varDecl(hasInitializer(ignoringImpCasts( anyOf( cStyleCastExpr(has(callExpr().bind("mcsssmallocinitializer2"))), callExpr().bind("mcsssmallocinitializer2") ) ))).bind("mcsssmallocinitializer3") )).bind("mcsssmallocinitializer1"), &HandlerForSSSMallocInitializer); Matcher.addMatcher( callExpr(allOf( hasAnyArgument( expr(anyOf( memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssfree2")))).bind("mcsssfree3"), hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcsssfree2")))).bind("mcsssfree3")), hasDescendant(declRefExpr().bind("mcsssfree2")) ))), argumentCountIs(1), hasAnyArgument(hasType(pointerType())) )).bind("mcsssfree1"), &HandlerForSSSFree); Matcher.addMatcher(binaryOperator(allOf( hasOperatorName("="), hasLHS(anyOf( memberExpr(expr(hasDescendant(declRefExpr().bind("mcssssettonull3")))).bind("mcssssettonull4"), hasDescendant(memberExpr(expr(hasDescendant(declRefExpr().bind("mcssssettonull3")))).bind("mcssssettonull4")), hasDescendant(declRefExpr().bind("mcssssettonull3")) )), hasLHS(expr(hasType(pointerType()))) )).bind("mcssssettonull1"), &HandlerForSSSSetToNull); } void HandleTranslationUnit(ASTContext &Context) override { Matcher.matchAST(Context); } private: CState1 m_state1; MCSSSNativePointer HandlerForSSSNativePointer; MCSSSArrayToPointerDecay HandlerForSSSArrayToPointerDecay; MCSSSVarDecl HandlerForSSSVarDecl; MCSSSPointerArithmetic HandlerForSSSPointerArithmetic; MCSSSMalloc HandlerForSSSMalloc; MCSSSMallocInitializer HandlerForSSSMallocInitializer; MCSSSFree HandlerForSSSFree; MCSSSSetToNull HandlerForSSSSetToNull; MatchFinder Matcher; }; /**********************************************************************************************************************/ class MyFrontendAction : public ASTFrontendAction { public: MyFrontendAction() {} ~MyFrontendAction() { if (ConvertToSCPP) { auto res = overwriteChangedFiles(); int q = 5; } } void EndSourceFileAction() override { TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID()).write(llvm::outs()); } std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) override { TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); return llvm::make_unique(TheRewriter); } bool overwriteChangedFiles() { return TheRewriter.overwriteChangedFiles(); } private: Rewriter TheRewriter; }; /**********************************************************************************************************************/ /*Main*/ int main(int argc, const char **argv) { CommonOptionsParser op(argc, argv, MatcherSampleCategory); ClangTool Tool(op.getCompilations(), op.getSourcePathList()); return Tool.run(newFrontendActionFactory().get()); } /*last line intentionally left blank*/