diff --git a/Makefile b/Makefile index 4cc62ca92..ba923e03b 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ BIN=${DESTDIR}/usr/bin OBJECTS = src/checkbufferoverrun.o \ src/checkclass.o \ + src/checkdangerousfunctions.o \ src/checkfunctionusage.o \ src/checkheaders.o \ src/checkmemoryleak.o \ @@ -24,6 +25,7 @@ TESTOBJ = test/testbufferoverrun.o \ test/testcharvar.o \ test/testclass.o \ test/testconstructors.o \ + test/testdangerousfunctions.o \ test/testdivision.o \ test/testfilelister.o \ test/testfunctionusage.o \ @@ -42,6 +44,7 @@ TESTOBJ = test/testbufferoverrun.o \ test/testunusedvar.o \ src/checkbufferoverrun.o \ src/checkclass.o \ + src/checkdangerousfunctions.o \ src/checkfunctionusage.o \ src/checkheaders.o \ src/checkmemoryleak.o \ @@ -93,10 +96,13 @@ src/checkbufferoverrun.o: src/checkbufferoverrun.cpp src/checkbufferoverrun.h sr src/checkclass.o: src/checkclass.cpp src/checkclass.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/errormessage.h g++ $(CXXFLAGS) -c -o src/checkclass.o src/checkclass.cpp +src/checkdangerousfunctions.o: src/checkdangerousfunctions.cpp src/checkdangerousfunctions.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/errormessage.h + g++ $(CXXFLAGS) -c -o src/checkdangerousfunctions.o src/checkdangerousfunctions.cpp + src/checkfunctionusage.o: src/checkfunctionusage.cpp src/checkfunctionusage.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/errormessage.h g++ $(CXXFLAGS) -c -o src/checkfunctionusage.o src/checkfunctionusage.cpp -src/checkheaders.o: src/checkheaders.cpp src/checkheaders.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h +src/checkheaders.o: src/checkheaders.cpp src/checkheaders.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/filelister.h g++ $(CXXFLAGS) -c -o src/checkheaders.o src/checkheaders.cpp src/checkmemoryleak.o: src/checkmemoryleak.cpp src/checkmemoryleak.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/errormessage.h @@ -105,7 +111,7 @@ src/checkmemoryleak.o: src/checkmemoryleak.cpp src/checkmemoryleak.h src/tokeniz src/checkother.o: src/checkother.cpp src/checkother.h src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/errormessage.h g++ $(CXXFLAGS) -c -o src/checkother.o src/checkother.cpp -src/cppcheck.o: src/cppcheck.cpp src/cppcheck.h src/settings.h src/errorlogger.h src/checkfunctionusage.h src/tokenize.h src/token.h src/preprocessor.h src/checkmemoryleak.h src/checkbufferoverrun.h src/checkclass.h src/checkheaders.h src/checkother.h src/filelister.h src/errormessage.h +src/cppcheck.o: src/cppcheck.cpp src/cppcheck.h src/settings.h src/errorlogger.h src/checkfunctionusage.h src/tokenize.h src/token.h src/preprocessor.h src/checkmemoryleak.h src/checkbufferoverrun.h src/checkdangerousfunctions.h src/checkclass.h src/checkheaders.h src/checkother.h src/filelister.h src/errormessage.h g++ $(CXXFLAGS) -c -o src/cppcheck.o src/cppcheck.cpp src/cppcheckexecutor.o: src/cppcheckexecutor.cpp src/cppcheckexecutor.h src/errorlogger.h src/cppcheck.h src/settings.h src/checkfunctionusage.h src/tokenize.h src/token.h @@ -144,6 +150,9 @@ test/testclass.o: test/testclass.cpp src/tokenize.h src/settings.h src/errorlogg test/testconstructors.o: test/testconstructors.cpp src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/checkclass.h test/testsuite.h g++ $(CXXFLAGS) -c -o test/testconstructors.o test/testconstructors.cpp +test/testdangerousfunctions.o: test/testdangerousfunctions.cpp src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/checkdangerousfunctions.h test/testsuite.h + g++ $(CXXFLAGS) -c -o test/testdangerousfunctions.o test/testdangerousfunctions.cpp + test/testdivision.o: test/testdivision.cpp src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/checkother.h test/testsuite.h g++ $(CXXFLAGS) -c -o test/testdivision.o test/testdivision.cpp diff --git a/src/checkbufferoverrun.cpp b/src/checkbufferoverrun.cpp index d589c47d7..1ae5a2e89 100644 --- a/src/checkbufferoverrun.cpp +++ b/src/checkbufferoverrun.cpp @@ -576,24 +576,3 @@ void CheckBufferOverrunClass::bufferOverrun() -//--------------------------------------------------------------------------- -// Dangerous functions -//--------------------------------------------------------------------------- - -void CheckBufferOverrunClass::dangerousFunctions() -{ - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) - { - if (Token::Match(tok, "gets|scanf (")) - { - std::ostringstream ostr; - ostr << _tokenizer->fileLine(tok) << ": Found '" << tok->str() << "'. You should use 'fgets' instead"; - _errorLogger->reportErr(ostr.str()); - } - } -} -//--------------------------------------------------------------------------- - - - - diff --git a/src/checkbufferoverrun.h b/src/checkbufferoverrun.h index 5a73133b5..a2f838d39 100644 --- a/src/checkbufferoverrun.h +++ b/src/checkbufferoverrun.h @@ -34,9 +34,6 @@ public: /** Check for buffer overruns */ void bufferOverrun(); - - /** Check that the code doesn't use dangerous functions that can cause buffer overruns (scanf and gets) */ - void dangerousFunctions(); private: /** Check for buffer overruns - locate struct variables and check them with the .._CheckScope function */ diff --git a/src/checkdangerousfunctions.cpp b/src/checkdangerousfunctions.cpp new file mode 100644 index 000000000..3d9bfec28 --- /dev/null +++ b/src/checkdangerousfunctions.cpp @@ -0,0 +1,92 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, + * Leandro Penz, Kimmo Varis + * + * 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 +#include +#include + + +#include // <- strtoul + +//--------------------------------------------------------------------------- + +// _callStack used when parsing into subfunctions. + + +CheckDangerousFunctionsClass::CheckDangerousFunctionsClass(const Tokenizer *tokenizer, const Settings &settings, ErrorLogger *errorLogger) + : _settings(settings) +{ + _tokenizer = tokenizer; + _errorLogger = errorLogger; +} + +CheckDangerousFunctionsClass::~CheckDangerousFunctionsClass() +{ + +} + +// Modified version of 'ReportError' that also reports the callstack +void CheckDangerousFunctionsClass::ReportError(const std::string &errmsg) +{ + std::ostringstream ostr; + std::list::const_iterator it; + for (it = _callStack.begin(); it != _callStack.end(); it++) + ostr << _tokenizer->fileLine(*it) << " -> "; + ostr << errmsg; + _errorLogger->reportErr(ostr.str()); +} +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Dangerous functions +//--------------------------------------------------------------------------- + +void CheckDangerousFunctionsClass::dangerousFunctions() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (Token::Match(tok, "mktemp (")) + { + std::ostringstream ostr; + ostr << _tokenizer->fileLine(tok) << ": Found 'mktemp'. You should use 'mkstemp' instead"; + _errorLogger->reportErr(ostr.str()); + } + else if (Token::Match(tok, "gets|scanf (")) + { + std::ostringstream ostr; + ostr << _tokenizer->fileLine(tok) << ": Found '" << tok->str() << "'. You should use 'fgets' instead"; + _errorLogger->reportErr(ostr.str()); + } + } +} +//--------------------------------------------------------------------------- + + + + diff --git a/src/checkdangerousfunctions.h b/src/checkdangerousfunctions.h new file mode 100644 index 000000000..1868c0e8f --- /dev/null +++ b/src/checkdangerousfunctions.h @@ -0,0 +1,53 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, + * Leandro Penz, Kimmo Varis + * + * 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 _callStack; +}; + +//--------------------------------------------------------------------------- +#endif + diff --git a/src/cppcheck.cpp b/src/cppcheck.cpp index 6a32afd7c..a628c0f69 100644 --- a/src/cppcheck.cpp +++ b/src/cppcheck.cpp @@ -23,6 +23,7 @@ #include "checkmemoryleak.h" #include "checkbufferoverrun.h" +#include "checkdangerousfunctions.h" #include "checkclass.h" #include "checkheaders.h" #include "checkother.h" @@ -365,6 +366,9 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) // Class for detecting buffer overruns and related problems CheckBufferOverrunClass checkBufferOverrun(&_tokenizer, _settings, this); + // Class for checking functions that should not be used + CheckDangerousFunctionsClass checkDangerousFunctions(&_tokenizer, _settings, this); + // Memory leak CheckMemoryLeakClass checkMemoryLeak(&_tokenizer, _settings, this); if (ErrorMessage::memleak() || ErrorMessage::mismatchAllocDealloc(_settings)) @@ -382,9 +386,6 @@ void CppCheck::checkFile(const std::string &code, const char FileName[]) if (ErrorMessage::arrayIndexOutOfBounds(_settings) || ErrorMessage::bufferOverrun(_settings)) checkBufferOverrun.bufferOverrun(); - // Dangerous functions, such as 'gets' and 'scanf' - checkBufferOverrun.dangerousFunctions(); - // Warning upon c-style pointer casts if (ErrorMessage::cstyleCast(_settings)) { diff --git a/test/testdangerousfunctions.cpp b/test/testdangerousfunctions.cpp new file mode 100644 index 000000000..d6e6d9f20 --- /dev/null +++ b/test/testdangerousfunctions.cpp @@ -0,0 +1,105 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam, + * Leandro Penz, Kimmo Varis + * + * 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 + +extern std::ostringstream errout; + +class TestDangerousFunctions : public TestFixture +{ +public: + TestDangerousFunctions() : TestFixture("TestDangerousFunctions") + { } + +private: + + + + void check(const char code[]) + { + // Tokenize.. + Tokenizer tokenizer; + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.simplifyTokenList(); + + // Assign variable ids + tokenizer.setVarId(); + + // Fill function list + tokenizer.fillFunctionList(); + + // Clear the error buffer.. + errout.str(""); + + // Check for buffer overruns.. + Settings settings; + settings._showAll = true; + CheckDangerousFunctionsClass checkDangerousFunctions(&tokenizer, settings, this); + checkDangerousFunctions.dangerousFunctions(); + } + + void run() + { + TEST_CASE(testmktemp); + TEST_CASE(testgets); + TEST_CASE(testscanf); + } + + + + void testmktemp() + { + check("void f()\n" + "{\n" + " char *x = mktemp(\"/tmp/zxcv\");\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:3]: Found 'mktemp'. You should use 'mkstemp' instead\n"), errout.str()); + } + + void testgets() + { + check("void f()\n" + "{\n" + " char *x = gets();\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:3]: Found 'gets'. You should use 'fgets' instead\n"), errout.str()); + } + + void testscanf() + { + check("void f()\n" + "{\n" + " char *x;\n" + " scanf(\"%s\", x);\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:4]: Found 'scanf'. You should use 'fgets' instead\n"), errout.str()); + } + +}; + +REGISTER_TEST(TestDangerousFunctions) + +