From 8f0f1840585b2de45c542f0c63029ce31d1ab9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 6 Jul 2011 08:55:17 +0200 Subject: [PATCH] 64-bit checking: Added simple check for assigning pointer address to int/long. Ticket: #2791 --- Makefile | 32 +++++++++----- lib/check64bit.cpp | 68 ++++++++++++++++++++++++++++ lib/check64bit.h | 91 ++++++++++++++++++++++++++++++++++++++ lib/lib.pri | 4 +- test/test64bit.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 289 insertions(+), 13 deletions(-) create mode 100644 lib/check64bit.cpp create mode 100644 lib/check64bit.h create mode 100644 test/test64bit.cpp diff --git a/Makefile b/Makefile index e46c6179a..6053f1c83 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,8 @@ MAN_SOURCE=man/cppcheck.1.xml ###### Object Files -LIBOBJ = lib/checkautovariables.o \ +LIBOBJ = lib/check64bit.o \ + lib/checkautovariables.o \ lib/checkbufferoverrun.o \ lib/checkclass.o \ lib/checkexceptionsafety.o \ @@ -78,6 +79,7 @@ CLIOBJ = cli/cmdlineparser.o \ cli/threadexecutor.o TESTOBJ = test/options.o \ + test/test64bit.o \ test/testautovariables.o \ test/testbufferoverrun.o \ test/testcharvar.o \ @@ -163,13 +165,16 @@ install: cppcheck ###### Build -lib/checkautovariables.o: lib/checkautovariables.cpp lib/checkautovariables.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h +lib/check64bit.o: lib/check64bit.cpp lib/check64bit.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/check64bit.o lib/check64bit.cpp + +lib/checkautovariables.o: lib/checkautovariables.cpp lib/checkautovariables.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/checkautovariables.o lib/checkautovariables.cpp -lib/checkbufferoverrun.o: lib/checkbufferoverrun.cpp lib/checkbufferoverrun.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/mathlib.h lib/executionpath.h +lib/checkbufferoverrun.o: lib/checkbufferoverrun.cpp lib/checkbufferoverrun.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/mathlib.h lib/symboldatabase.h lib/executionpath.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/checkbufferoverrun.o lib/checkbufferoverrun.cpp -lib/checkclass.o: lib/checkclass.cpp lib/checkclass.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h +lib/checkclass.o: lib/checkclass.cpp lib/checkclass.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/checkclass.o lib/checkclass.cpp lib/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/checkexceptionsafety.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h @@ -190,7 +195,7 @@ lib/checkother.o: lib/checkother.cpp lib/checkother.h lib/check.h lib/token.h li lib/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/checkpostfixoperator.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/checkpostfixoperator.o lib/checkpostfixoperator.cpp -lib/checkstl.o: lib/checkstl.cpp lib/checkstl.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/executionpath.h lib/symboldatabase.h +lib/checkstl.o: lib/checkstl.cpp lib/checkstl.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/executionpath.h lib/symboldatabase.h lib/mathlib.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/checkstl.o lib/checkstl.cpp lib/checkuninitvar.o: lib/checkuninitvar.cpp lib/checkuninitvar.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/mathlib.h lib/executionpath.h lib/checknullpointer.h @@ -217,10 +222,10 @@ lib/path.o: lib/path.cpp lib/path.h lib/preprocessor.o: lib/preprocessor.cpp lib/preprocessor.h lib/tokenize.h lib/token.h lib/path.h lib/errorlogger.h lib/settings.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/preprocessor.o lib/preprocessor.cpp -lib/settings.o: lib/settings.cpp lib/settings.h +lib/settings.o: lib/settings.cpp lib/settings.h lib/path.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/settings.o lib/settings.cpp -lib/symboldatabase.o: lib/symboldatabase.cpp lib/symboldatabase.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/check.h +lib/symboldatabase.o: lib/symboldatabase.cpp lib/symboldatabase.h lib/token.h lib/mathlib.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/check.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_LIB} -c -o lib/symboldatabase.o lib/symboldatabase.cpp lib/timer.o: lib/timer.cpp lib/timer.h @@ -253,6 +258,9 @@ cli/threadexecutor.o: cli/threadexecutor.cpp cli/cppcheckexecutor.h lib/errorlog test/options.o: test/options.cpp test/options.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/options.o test/options.cpp +test/test64bit.o: test/test64bit.cpp lib/tokenize.h lib/check64bit.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/test64bit.o test/test64bit.cpp + test/testautovariables.o: test/testautovariables.cpp lib/tokenize.h lib/checkautovariables.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testautovariables.o test/testautovariables.cpp @@ -262,13 +270,13 @@ test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/tokenize.h lib/checkbuf test/testcharvar.o: test/testcharvar.cpp lib/tokenize.h lib/checkother.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testcharvar.o test/testcharvar.cpp -test/testclass.o: test/testclass.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h +test/testclass.o: test/testclass.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testclass.o test/testclass.cpp test/testcmdlineparser.o: test/testcmdlineparser.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testcmdlineparser.o test/testcmdlineparser.cpp -test/testconstructors.o: test/testconstructors.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h +test/testconstructors.o: test/testconstructors.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testconstructors.o test/testconstructors.cpp test/testcppcheck.o: test/testcppcheck.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h lib/path.h @@ -292,7 +300,7 @@ test/testincompletestatement.o: test/testincompletestatement.cpp test/testsuite. test/testmathlib.o: test/testmathlib.cpp lib/mathlib.h test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testmathlib.o test/testmathlib.cpp -test/testmemleak.o: test/testmemleak.cpp lib/tokenize.h lib/checkmemoryleak.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h +test/testmemleak.o: test/testmemleak.cpp lib/tokenize.h lib/checkmemoryleak.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testmemleak.o test/testmemleak.cpp test/testnullpointer.o: test/testnullpointer.cpp lib/tokenize.h lib/checknullpointer.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h @@ -337,7 +345,7 @@ test/testsuite.o: test/testsuite.cpp test/testsuite.h lib/errorlogger.h lib/sett test/testsuppressions.o: test/testsuppressions.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testsuppressions.o test/testsuppressions.cpp -test/testsymboldatabase.o: test/testsymboldatabase.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h test/testutils.h lib/tokenize.h lib/token.h lib/symboldatabase.h +test/testsymboldatabase.o: test/testsymboldatabase.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h test/testutils.h lib/tokenize.h lib/token.h lib/symboldatabase.h lib/mathlib.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testsymboldatabase.o test/testsymboldatabase.cpp test/testthreadexecutor.o: test/testthreadexecutor.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h @@ -355,7 +363,7 @@ test/testuninitvar.o: test/testuninitvar.cpp lib/tokenize.h lib/checkuninitvar.h test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/tokenize.h test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h lib/checkunusedfunctions.h lib/check.h lib/token.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testunusedfunctions.o test/testunusedfunctions.cpp -test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h +test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h lib/mathlib.h test/testsuite.h test/redirect.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) ${INCLUDE_FOR_TEST} -c -o test/testunusedprivfunc.o test/testunusedprivfunc.cpp test/testunusedvar.o: test/testunusedvar.cpp test/testsuite.h lib/errorlogger.h lib/settings.h test/redirect.h lib/tokenize.h lib/checkother.h lib/check.h lib/token.h diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp new file mode 100644 index 000000000..9dc0c41ea --- /dev/null +++ b/lib/check64bit.cpp @@ -0,0 +1,68 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 Daniel Marjamäki and 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 . + */ + +//--------------------------------------------------------------------------- +// 64-bit portability +//--------------------------------------------------------------------------- + +#include "check64bit.h" +#include "symboldatabase.h" + +//--------------------------------------------------------------------------- + +// Register this check class (by creating a static instance of it) +namespace +{ +Check64BitPortability instance; +} + +void Check64BitPortability::pointerassignment() +{ + if (!_settings->_checkCodingStyle) + return; + + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (Token::Match(tok, "[;{}] %var% = %var% ;")) + { + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + + const Variable *var1(symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId())); + const Variable *var2(symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId())); + if (!var1 || !var2) + continue; + + // Check if var1 is an int/long/DWORD variable + if (!Token::Match(var1->nameToken()->previous(), "int|long|DWORD")) + continue; + + // Check if var2 is a pointer variable + if (!Token::simpleMatch(var2->nameToken()->previous(), "*")) + continue; + + pointerassignmentError(tok->next()); + } + } +} + +void Check64BitPortability::pointerassignmentError(const Token *tok) +{ + reportError(tok, Severity::portability, + "addresstoint", "Assigning address to int/long is not portable" + ); +} diff --git a/lib/check64bit.h b/lib/check64bit.h new file mode 100644 index 000000000..d2df5385b --- /dev/null +++ b/lib/check64bit.h @@ -0,0 +1,91 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 Daniel Marjamäki and 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 check64bitH +#define check64bitH +//--------------------------------------------------------------------------- + +#include "check.h" + + +/// @addtogroup Checks +/// @{ + +/** + * @brief Check for 64-bit portability issues + */ + +class Check64BitPortability : public Check +{ +public: + /** This constructor is used when registering the Check64BitPortability */ + Check64BitPortability() : Check(myName()) + { + } + + /** This constructor is used when running checks. */ + Check64BitPortability(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + : Check(myName(), tokenizer, settings, errorLogger) + { + } + + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + { + Check64BitPortability check64BitPortability(tokenizer, settings, errorLogger); + check64BitPortability.pointerassignment(); + } + + /** @brief Run checks against the simplified token list */ + void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + { + (void)tokenizer; + (void)settings; + (void)errorLogger; + } + + /** Check for obsolete functions */ + void pointerassignment(); + +private: + + void pointerassignmentError(const Token *tok); + + void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) + { + Check64BitPortability c(0, settings, errorLogger); + c.pointerassignmentError(0); + } + + std::string myName() const + { + return "64-bit portability"; + } + + std::string classInfo() const + { + return "Check if there is 64-bit portability issues:\n" + " * assign address to/from int/long"; + } +}; +/// @} +//--------------------------------------------------------------------------- +#endif + diff --git a/lib/lib.pri b/lib/lib.pri index 750e3c790..7afb12a4a 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -3,6 +3,7 @@ LIBS += -L../externals -lpcre INCLUDEPATH += ../externals ../externals/tinyxml HEADERS += $${BASEPATH}check.h \ + $${BASEPATH}check64bit.h \ $${BASEPATH}checkautovariables.h \ $${BASEPATH}checkbufferoverrun.h \ $${BASEPATH}checkclass.h \ @@ -27,7 +28,8 @@ HEADERS += $${BASEPATH}check.h \ $${BASEPATH}token.h \ $${BASEPATH}tokenize.h -SOURCES += $${BASEPATH}checkautovariables.cpp \ +SOURCES += $${BASEPATH}check64bit.cpp \ + $${BASEPATH}checkautovariables.cpp \ $${BASEPATH}checkbufferoverrun.cpp \ $${BASEPATH}checkclass.cpp \ $${BASEPATH}checkexceptionsafety.cpp \ diff --git a/test/test64bit.cpp b/test/test64bit.cpp new file mode 100644 index 000000000..fe1f8e1cb --- /dev/null +++ b/test/test64bit.cpp @@ -0,0 +1,107 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2011 Daniel Marjamäki and 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 "tokenize.h" +#include "check64bit.h" +#include "testsuite.h" +#include + +extern std::ostringstream errout; + +class Test64BitPortability : public TestFixture +{ +public: + Test64BitPortability() : TestFixture("Test64BitPortability") + { } + +private: + + + void run() + { + TEST_CASE(novardecl); + TEST_CASE(functionpar); + TEST_CASE(structmember); + } + + void check(const char code[]) + { + // Clear the error buffer.. + errout.str(""); + + Settings settings; + settings._checkCodingStyle = true; + + // Tokenize.. + Tokenizer tokenizer(&settings, this); + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.setVarId(); + + // Check char variable usage.. + Check64BitPortability check64BitPortability(&tokenizer, &settings, this); + check64BitPortability.pointerassignment(); + } + + void novardecl() + { + // if the variable declarations can't be seen then skip the warning + check("void foo()\n" + "{\n" + " a = p;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + + void functionpar() + { + check("int foo(int *p)\n" + "{\n" + " int a = p;\n" + " return a + 4;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (portability) Assigning address to int/long is not portable\n", errout.str()); + + check("int foo(int p[])\n" + "{\n" + " int a = p;\n" + " return a + 4;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3]: (portability) Assigning address to int/long is not portable\n", "", errout.str()); + + check("void foo(int x)\n" + "{\n" + " int *p = x;\n" + " *p = 0;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3]: (portability) Assigning int/long to pointer is not portable\n", "", errout.str()); + } + + void structmember() + { + check("struct Foo { int *p };\n" + "void f(struct Foo *foo) {\n" + " int i = foo->p;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:3]: (portability) Assigning address to int/long is not portable\n", "", errout.str()); + } +}; + +REGISTER_TEST(Test64BitPortability) +