From 9647cce4b214f4eaf28d32a85472b7e39e393950 Mon Sep 17 00:00:00 2001 From: alonlib12 Date: Sun, 10 Jan 2021 01:24:16 +0200 Subject: [PATCH] selfassignmentCheck --- CMakeSettings.json | 22 +++++ lib/checkselfassignment.cpp | 126 ++++++++++++++++++++++++ lib/checkselfassignment.h | 64 ++++++++++++ lib/cppcheck.vcxproj | 4 +- lib/cppcheck.vcxproj.filters | 15 +++ samples/selfAssignmentOperator/bad.cpp | 23 +++++ samples/selfAssignmentOperator/bad.hpp | 12 +++ samples/selfAssignmentOperator/good.cpp | 23 +++++ samples/selfAssignmentOperator/good.hpp | 12 +++ 9 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 CMakeSettings.json create mode 100644 lib/checkselfassignment.cpp create mode 100644 lib/checkselfassignment.h create mode 100644 samples/selfAssignmentOperator/bad.cpp create mode 100644 samples/selfAssignmentOperator/bad.hpp create mode 100644 samples/selfAssignmentOperator/good.cpp create mode 100644 samples/selfAssignmentOperator/good.hpp diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 00000000000..f8e4110d54f --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "variables": [ + { + "name": "BUILD_TESTS", + "value": "True", + "type": "BOOL" + } + ] + } + ] +} \ No newline at end of file diff --git a/lib/checkselfassignment.cpp b/lib/checkselfassignment.cpp new file mode 100644 index 00000000000..0df4505b51f --- /dev/null +++ b/lib/checkselfassignment.cpp @@ -0,0 +1,126 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2020 Cppcheck team. + * + * 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 3 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, see . + */ + +#include "checkselfassignment.h" + +#include "astutils.h" +#include "errorlogger.h" +#include "library.h" +#include "settings.h" +#include "symboldatabase.h" +#include "token.h" +#include "tokenize.h" +#include "utils.h" + +#include +#include +#include + + //--------------------------------------------------------------------------- +using namespace std; + +// Register this check class into cppcheck by creating a static instance of it.. +namespace { + CheckSelfAssignment instance; +} + +// CWE ID used: +static const CWE CWE398(398U); // Indicator of Poor Code Quality +static const CWE CWE401(401U); // Improper Release of Memory Before Removing Last Reference ('Memory Leak') +static const CWE CWE771(771U); // Missing Reference to Active Allocated Resource +static const CWE CWE772(772U); // Missing Release of Resource after Effective Lifetimes + +static const std::set deallocations_func_list = { + "delete", "free" +}; + + +#include +void CheckSelfAssignment::check() +{ + const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); + for (const Scope* scope : symbolDatabase->classAndStructScopes) + { + for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) + { + if (tok->str() == "operator=") + { + cout << "isassignmentOp() " << tok->isAssignmentOp() << endl; + auto func = tok->function(); + if (func) + { + const Token* argTok; + if (Token::Match(func->argDef, "( const Bug & %name%")) + { + argTok = func->argDef->tokAt(4); + } + else + { + continue; + } + auto fieldList = func->functionScope->functionOf->varlist; + bool insideSelfCheckScope = false; + string selfCheckPattern = "if ( this != & " + argTok->str(); + const Token* endOfSelfCheckScope = NULL; + for (const Token* itr = func->functionScope->bodyStart; itr && itr != func->functionScope->bodyEnd; itr = itr->next()) + { + + if (Token::Match(itr, selfCheckPattern.c_str())) + { + insideSelfCheckScope = true; + const Token* parenthesisTok = itr->tokAt(7); + if (parenthesisTok && parenthesisTok->str() == "{") + { + endOfSelfCheckScope = parenthesisTok->link(); + } + else + { + const Token* iter; + for (iter = parenthesisTok; iter && iter->str() != ";"; iter = iter->next()) + {} + if (iter) + { + endOfSelfCheckScope = iter; + } + } + } + else if (itr == endOfSelfCheckScope) + { + insideSelfCheckScope = false; + } + else if (!insideSelfCheckScope && deallocations_func_list.find(itr->str()) != deallocations_func_list.end()) + { + if (itr->next() && fieldList.find(itr->next())) //ALON CONTINUE HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + selfAssignmentError(itr); + } + } + } + } + } + } +} + + + +void CheckSelfAssignment::selfAssignmentError(const Token* tok) +{ + reportError(tok, Severity::error, "selfAssignmentError", + "Assignment operator self assignment issue " + , CWE398, false); +} + diff --git a/lib/checkselfassignment.h b/lib/checkselfassignment.h new file mode 100644 index 00000000000..24798485fb3 --- /dev/null +++ b/lib/checkselfassignment.h @@ -0,0 +1,64 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2020 Cppcheck team. + * + * 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 3 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, see . + */ + + //--------------------------------------------------------------------------- +#ifndef checkselfassignmentH +#define checkselfassignmentH +//--------------------------------------------------------------------------- + +#include "check.h" + +class CPPCHECKLIB CheckSelfAssignment : public Check { +public: + + /** This constructor is used when registering the CheckClass */ + CheckSelfAssignment() : Check(myName()) { + } + + /** This constructor is used when running checks. */ + CheckSelfAssignment(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) { + } + + void check(); + + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger) OVERRIDE { + CheckSelfAssignment checkSelfAssignment(tokenizer, settings, errorLogger); + // Checks + checkSelfAssignment.check(); + } + + std::string classInfo() const OVERRIDE { + return "Assignment operator should check for self assignment"; + } + + +private: + void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const OVERRIDE { + ErrorPath errorPath; + CheckSelfAssignment checkSelfAssignment(nullptr, settings, errorLogger); + } + + void selfAssignmentError(const Token* tok); + static std::string myName() { + return "CheckSelfAssignment"; + } +}; + +#endif // checkselfassignmentH \ No newline at end of file diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index f4d1e87ffbe..6500caff08f 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -59,6 +59,7 @@ + @@ -119,6 +120,7 @@ + @@ -569,4 +571,4 @@ xcopy "$(SolutionDir)platforms" "$(OutDir)platforms" /E /I /D /Y - + \ No newline at end of file diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index 39e2fcd8150..5f376d41558 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -179,6 +179,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -346,6 +355,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/samples/selfAssignmentOperator/bad.cpp b/samples/selfAssignmentOperator/bad.cpp new file mode 100644 index 00000000000..ef4ba423a25 --- /dev/null +++ b/samples/selfAssignmentOperator/bad.cpp @@ -0,0 +1,23 @@ +#include +#include "bad.hpp" + +Bug::Bug(int l) : length(l), array(new int[length]) +{ +} + +Bug::~Bug() +{ + delete[] array; +} + +Bug& Bug::operator=(const Bug& rhs) +{ + if (this == &rhs) // Oh no, inverse condition + { + length = rhs.length; + delete[] array; + array = new int[length]; + std::copy_n(rhs.array, length, array); + } + return *this; +} \ No newline at end of file diff --git a/samples/selfAssignmentOperator/bad.hpp b/samples/selfAssignmentOperator/bad.hpp new file mode 100644 index 00000000000..130eb0ab469 --- /dev/null +++ b/samples/selfAssignmentOperator/bad.hpp @@ -0,0 +1,12 @@ +#include +class Bug +{ + int length; + int* array; + +public: + Bug(int l); + ~Bug(); + Bug(const Bug& rhs) = delete; + Bug& operator=(const Bug& rhs); +}; \ No newline at end of file diff --git a/samples/selfAssignmentOperator/good.cpp b/samples/selfAssignmentOperator/good.cpp new file mode 100644 index 00000000000..d58ba58d6eb --- /dev/null +++ b/samples/selfAssignmentOperator/good.cpp @@ -0,0 +1,23 @@ +#include +#include "bad.hpp" + +Bug::Bug(int l) : length(l), array(new int[length]) +{ +} + +Bug::~Bug() +{ + delete[] array; +} + +Bug& Bug::operator=(const Bug& rhs) +{ + if (this != &rhs) + { + length = rhs.length; + delete[] array; + array = new int[length]; + std::copy_n(rhs.array, length, array); + } + return *this; +} \ No newline at end of file diff --git a/samples/selfAssignmentOperator/good.hpp b/samples/selfAssignmentOperator/good.hpp new file mode 100644 index 00000000000..130eb0ab469 --- /dev/null +++ b/samples/selfAssignmentOperator/good.hpp @@ -0,0 +1,12 @@ +#include +class Bug +{ + int length; + int* array; + +public: + Bug(int l); + ~Bug(); + Bug(const Bug& rhs) = delete; + Bug& operator=(const Bug& rhs); +}; \ No newline at end of file