diff --git a/Makefile b/Makefile index 8b6fad9a1..b5a2394c4 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ OBJECTS = src/checkbufferoverrun.o \ src/checkmemoryleak.o \ src/checkother.o \ src/checkstl.o \ + src/checkvalidate.o \ src/cppcheck.o \ src/cppcheckexecutor.o \ src/errorlogger.o \ @@ -45,6 +46,7 @@ TESTOBJ = test/testbufferoverrun.o \ test/testtokenize.o \ test/testunusedprivfunc.o \ test/testunusedvar.o \ + test/testvalidate.o \ src/checkbufferoverrun.o \ src/checkclass.o \ src/checkdangerousfunctions.o \ @@ -53,6 +55,7 @@ TESTOBJ = test/testbufferoverrun.o \ src/checkmemoryleak.o \ src/checkother.o \ src/checkstl.o \ + src/checkvalidate.o \ src/cppcheck.o \ src/cppcheckexecutor.o \ src/errorlogger.o \ @@ -118,6 +121,9 @@ src/checkother.o: src/checkother.cpp src/checkother.h src/tokenize.h src/setting src/checkstl.o: src/checkstl.cpp src/checkstl.h src/errorlogger.h src/settings.h src/token.h src/tokenize.h g++ $(CXXFLAGS) -c -o src/checkstl.o src/checkstl.cpp +src/checkvalidate.o: src/checkvalidate.cpp src/checkvalidate.h src/errorlogger.h src/settings.h src/token.h src/tokenize.h + g++ $(CXXFLAGS) -c -o src/checkvalidate.o src/checkvalidate.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/checkdangerousfunctions.h src/checkclass.h src/checkheaders.h src/checkother.h src/checkstl.h src/filelister.h g++ $(CXXFLAGS) -c -o src/cppcheck.o src/cppcheck.cpp @@ -214,6 +220,9 @@ test/testunusedprivfunc.o: test/testunusedprivfunc.cpp src/tokenize.h src/settin test/testunusedvar.o: test/testunusedvar.cpp test/testsuite.h src/errorlogger.h src/settings.h src/tokenize.h src/token.h src/checkother.h g++ $(CXXFLAGS) -c -o test/testunusedvar.o test/testunusedvar.cpp +test/testvalidate.o: test/testvalidate.cpp src/tokenize.h src/settings.h src/errorlogger.h src/token.h src/checkvalidate.h test/testsuite.h + g++ $(CXXFLAGS) -c -o test/testvalidate.o test/testvalidate.cpp + src/errorlogger.h: tools/errmsg tools/errmsg mv errorlogger.h src/ diff --git a/src/checkvalidate.cpp b/src/checkvalidate.cpp new file mode 100644 index 000000000..65800bfdb --- /dev/null +++ b/src/checkvalidate.cpp @@ -0,0 +1,79 @@ +/* + * 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 tokens(); + while (tok) + { + unsigned int varId = 0; + + // Search for a variable declaration + while (tok) + { + if (Token::Match(tok, "int %var% ;")) + { + varId = tok->next()->varId(); + break; + } + tok = tok->next(); + } + + // Skip ahead a little with tok.. + tok = tok->tokAt(2); + + // Now take a look at the variable usage.. + if (varId == 0) + continue; + + // Search for bad input.. + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (Token::Match(tok2, "cin >> %varid%", varId)) + _errorLogger->unvalidatedInput(_tokenizer, tok2, tok2->strAt(2)); + if (Token::Match(tok2, "fscanf ( %var% , %str% , %varid%", varId)) + _errorLogger->unvalidatedInput(_tokenizer, tok2, tok2->strAt(6)); + if (Token::Match(tok2, "scanf ( %str% , %varid%", varId)) + _errorLogger->unvalidatedInput(_tokenizer, tok2, tok2->strAt(4)); + } + } +} + + + diff --git a/src/checkvalidate.h b/src/checkvalidate.h new file mode 100644 index 000000000..5714ab128 --- /dev/null +++ b/src/checkvalidate.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 -#include -#include "settings.h" -class Token; -class Tokenizer; - -/** - * This is an interface, which the class responsible of error logging - * should implement. - */ -class ErrorLogger -{ -public: - - /** - * Wrapper for error messages, provided by reportErr() - */ - class ErrorMessage - { - public: - /** - * File name and line number. - */ - class FileLocation - { - public: - std::string file; - unsigned int line; - }; - - ErrorMessage(const std::list &callStack, const std::string &severity, const std::string &msg, const std::string &id); - std::string toXML() const; - std::string toText() const; - private: - std::list _callStack; - std::string _severity; - std::string _msg; - std::string _id; - }; - - ErrorLogger() { } - virtual ~ErrorLogger() { } - - /** - * Information about progress is directed here. - * Override this to receive the progress messages. - * - * @param outmsg, E.g. "Checking main.cpp..." - */ - virtual void reportOut(const std::string &outmsg) = 0; - - /** - * Information about found errors and warnings is directed - * here. Override this to receive the errormessages. - * - * @param msg Location and other information about the found. - * error - */ - virtual void reportErr(const ErrorLogger::ErrorMessage &msg) = 0; - - void arrayIndexOutOfBounds(const Tokenizer *tokenizer, const std::list &Location) - { - _writemsg(tokenizer, Location, "all", "Array index out of bounds", "arrayIndexOutOfBounds"); - } - static bool arrayIndexOutOfBounds(const Settings &s) - { - return s._showAll; - } - - void bufferOverrun(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "all", "Buffer overrun", "bufferOverrun"); - } - static bool bufferOverrun(const Settings &s) - { - return s._showAll; - } - - void outOfBounds(const Tokenizer *tokenizer, const Token *Location, const std::string &what) - { - _writemsg(tokenizer, Location, "error", "" + what + " is out of bounds", "outOfBounds"); - } - static bool outOfBounds() - { - return true; - } - - void stlOutOfBounds(const Tokenizer *tokenizer, const Token *Location, const std::string &what) - { - _writemsg(tokenizer, Location, "error", "" + what + " is out of bounds", "stlOutOfBounds"); - } - static bool stlOutOfBounds() - { - return true; - } - - void noConstructor(const Tokenizer *tokenizer, const Token *Location, const std::string &classname) - { - _writemsg(tokenizer, Location, "style", "The class '" + classname + "' has no constructor", "noConstructor"); - } - static bool noConstructor(const Settings &s) - { - return s._checkCodingStyle; - } - - void uninitVar(const Tokenizer *tokenizer, const Token *Location, const std::string &classname, const std::string &varname) - { - _writemsg(tokenizer, Location, "style", "Member variable not initialized in the constructor '" + classname + "::" + varname + "'", "uninitVar"); - } - static bool uninitVar(const Settings &s) - { - return s._checkCodingStyle; - } - - void unusedPrivateFunction(const Tokenizer *tokenizer, const Token *Location, const std::string &classname, const std::string &funcname) - { - _writemsg(tokenizer, Location, "style", "Unused private function '" + classname + "::" + funcname + "'", "unusedPrivateFunction"); - } - static bool unusedPrivateFunction(const Settings &s) - { - return s._checkCodingStyle; - } - - void memsetClass(const Tokenizer *tokenizer, const Token *Location, const std::string &memfunc) - { - _writemsg(tokenizer, Location, "error", "Using '" + memfunc + "' on class", "memsetClass"); - } - static bool memsetClass() - { - return true; - } - - void memsetStruct(const Tokenizer *tokenizer, const Token *Location, const std::string &memfunc, const std::string &classname) - { - _writemsg(tokenizer, Location, "error", "Using '" + memfunc + "' on struct that contains a 'std::" + classname + "'", "memsetStruct"); - } - static bool memsetStruct() - { - return true; - } - - void operatorEq(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "'operator=' should return something", "operatorEq"); - } - static bool operatorEq(const Settings &s) - { - return s._checkCodingStyle; - } - - void virtualDestructor(const Tokenizer *tokenizer, const Token *Location, const std::string &Base, const std::string &Derived) - { - _writemsg(tokenizer, Location, "error", "Class " + Base + " which is inherited by class " + Derived + " does not have a virtual destructor", "virtualDestructor"); - } - static bool virtualDestructor() - { - return true; - } - - void unusedFunction(const std::string &filename, const std::string &funcname) - { - _writemsg("[" + filename + "]: The function '" + funcname + "' is never used", "unusedFunction"); - } - static bool unusedFunction(const Settings &s) - { - return s._checkCodingStyle || s._showAll; - } - - void mismatchAllocDealloc(const Tokenizer *tokenizer, const std::list &Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Mismatching allocation and deallocation: " + varname + "", "mismatchAllocDealloc"); - } - static bool mismatchAllocDealloc() - { - return true; - } - - void memleak(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Memory leak: " + varname + "", "memleak"); - } - static bool memleak() - { - return true; - } - - void memleakall(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "all", "Memory leak: " + varname + "", "memleakall"); - } - static bool memleakall(const Settings &s) - { - return s._showAll; - } - - void resourceLeak(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Resource leak: " + varname + "", "resourceLeak"); - } - static bool resourceLeak() - { - return true; - } - - void deallocDealloc(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Deallocating a deallocated pointer: " + varname + "", "deallocDealloc"); - } - static bool deallocDealloc() - { - return true; - } - - void deallocuse(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Using '" + varname + "' after it is deallocated / released", "deallocuse"); - } - static bool deallocuse() - { - return true; - } - - void mismatchSize(const Tokenizer *tokenizer, const Token *Location, const std::string &sz) - { - _writemsg(tokenizer, Location, "error", "The given size " + sz + " is mismatching", "mismatchSize"); - } - static bool mismatchSize() - { - return true; - } - - void cstyleCast(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "C-style pointer casting", "cstyleCast"); - } - static bool cstyleCast(const Settings &s) - { - return s._checkCodingStyle; - } - - void redundantIfDelete0(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Redundant condition. It is safe to deallocate a NULL pointer", "redundantIfDelete0"); - } - static bool redundantIfDelete0(const Settings &s) - { - return s._checkCodingStyle; - } - - void redundantIfRemove(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Redundant condition. The remove function in the STL will not do anything if element doesn't exist", "redundantIfRemove"); - } - static bool redundantIfRemove(const Settings &s) - { - return s._checkCodingStyle; - } - - void dangerousUsageStrtol(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "error", "Invalid radix in call to strtol or strtoul. Must be 0 or 2-36", "dangerousUsageStrtol"); - } - static bool dangerousUsageStrtol() - { - return true; - } - - void ifNoAction(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Found redundant if condition - 'if (condition);'", "ifNoAction"); - } - static bool ifNoAction(const Settings &s) - { - return s._checkCodingStyle; - } - - void sprintfOverlappingData(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "error", "Overlapping data buffer " + varname + "", "sprintfOverlappingData"); - } - static bool sprintfOverlappingData() - { - return true; - } - - void udivError(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "error", "Unsigned division. The result will be wrong.", "udivError"); - } - static bool udivError() - { - return true; - } - - void udivWarning(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "all style", "Warning: Division with signed and unsigned operators", "udivWarning"); - } - static bool udivWarning(const Settings &s) - { - return s._checkCodingStyle || s._showAll; - } - - void unusedStructMember(const Tokenizer *tokenizer, const Token *Location, const std::string &structname, const std::string &varname) - { - _writemsg(tokenizer, Location, "style", "struct or union member '" + structname + "::" + varname + "' is never used", "unusedStructMember"); - } - static bool unusedStructMember(const Settings &s) - { - return s._checkCodingStyle; - } - - void passedByValue(const Tokenizer *tokenizer, const Token *Location, const std::string &parname) - { - _writemsg(tokenizer, Location, "style", "Function parameter '" + parname + "' is passed by value. It could be passed by reference instead.", "passedByValue"); - } - static bool passedByValue(const Settings &s) - { - return s._checkCodingStyle; - } - - void constStatement(const Tokenizer *tokenizer, const Token *Location, const std::string &type) - { - _writemsg(tokenizer, Location, "style", "Redundant code: Found a statement that begins with " + type + " constant", "constStatement"); - } - static bool constStatement(const Settings &s) - { - return s._checkCodingStyle; - } - - void charArrayIndex(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Warning - using char variable as array index", "charArrayIndex"); - } - static bool charArrayIndex(const Settings &s) - { - return s._checkCodingStyle; - } - - void charBitOp(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Warning - using char variable in bit operation", "charBitOp"); - } - static bool charBitOp(const Settings &s) - { - return s._checkCodingStyle; - } - - void variableScope(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) - { - _writemsg(tokenizer, Location, "never", "The scope of the variable " + varname + " can be limited", "variableScope"); - } - static bool variableScope() - { - return false; - } - - void conditionAlwaysTrueFalse(const Tokenizer *tokenizer, const Token *Location, const std::string &truefalse) - { - _writemsg(tokenizer, Location, "style", "Condition is always " + truefalse + "", "conditionAlwaysTrueFalse"); - } - static bool conditionAlwaysTrueFalse(const Settings &s) - { - return s._checkCodingStyle; - } - - void strPlusChar(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "error", "Unusual pointer arithmetic", "strPlusChar"); - } - static bool strPlusChar() - { - return true; - } - - void returnLocalVariable(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "error", "Returning pointer to local array variable", "returnLocalVariable"); - } - static bool returnLocalVariable() - { - return true; - } - - void dangerousFunctionmktemp(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Found 'mktemp'. You should use 'mkstemp' instead", "dangerousFunctionmktemp"); - } - static bool dangerousFunctionmktemp(const Settings &s) - { - return s._checkCodingStyle; - } - - void dangerousFunctiongets(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Found 'gets'. You should use 'fgets' instead", "dangerousFunctiongets"); - } - static bool dangerousFunctiongets(const Settings &s) - { - return s._checkCodingStyle; - } - - void dangerousFunctionscanf(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "style", "Found 'scanf'. You should use 'fgets' instead", "dangerousFunctionscanf"); - } - static bool dangerousFunctionscanf(const Settings &s) - { - return s._checkCodingStyle; - } - - void iteratorUsage(const Tokenizer *tokenizer, const Token *Location, const std::string &container1, const std::string &container2) - { - _writemsg(tokenizer, Location, "error", "Same iterator is used with both " + container1 + " and " + container2 + "", "iteratorUsage"); - } - static bool iteratorUsage() - { - return true; - } - - void erase(const Tokenizer *tokenizer, const Token *Location) - { - _writemsg(tokenizer, Location, "error", "Dangerous usage of erase", "erase"); - } - static bool erase() - { - return true; - } - - void pushback(const Tokenizer *tokenizer, const Token *Location, const std::string &iterator_name) - { - _writemsg(tokenizer, Location, "error", "After push_back or push_front, the iterator '" + iterator_name + "' may be invalid", "pushback"); - } - static bool pushback() - { - return true; - } - - - static std::string callStackToString(const std::list &callStack); - -private: - void _writemsg(const Tokenizer *tokenizer, const Token *tok, const char severity[], const std::string msg, const std::string &id); - void _writemsg(const Tokenizer *tokenizer, const std::list &callstack, const char severity[], const std::string msg, const std::string &id); - void _writemsg(const std::string msg, const std::string &id); -}; -#endif +/* + * 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 "settings.h" +class Token; +class Tokenizer; + +/** + * This is an interface, which the class responsible of error logging + * should implement. + */ +class ErrorLogger +{ +public: + + /** + * Wrapper for error messages, provided by reportErr() + */ + class ErrorMessage + { + public: + /** + * File name and line number. + */ + class FileLocation + { + public: + std::string file; + unsigned int line; + }; + + ErrorMessage(const std::list &callStack, const std::string &severity, const std::string &msg, const std::string &id); + std::string toXML() const; + std::string toText() const; + private: + std::list _callStack; + std::string _severity; + std::string _msg; + std::string _id; + }; + + ErrorLogger() { } + virtual ~ErrorLogger() { } + + /** + * Information about progress is directed here. + * Override this to receive the progress messages. + * + * @param outmsg, E.g. "Checking main.cpp..." + */ + virtual void reportOut(const std::string &outmsg) = 0; + + /** + * Information about found errors and warnings is directed + * here. Override this to receive the errormessages. + * + * @param msg Location and other information about the found. + * error + */ + virtual void reportErr(const ErrorLogger::ErrorMessage &msg) = 0; + + void arrayIndexOutOfBounds(const Tokenizer *tokenizer, const std::list &Location) + { + _writemsg(tokenizer, Location, "all", "Array index out of bounds", "arrayIndexOutOfBounds"); + } + static bool arrayIndexOutOfBounds(const Settings &s) + { + return s._showAll; + } + + void bufferOverrun(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "all", "Buffer overrun", "bufferOverrun"); + } + static bool bufferOverrun(const Settings &s) + { + return s._showAll; + } + + void outOfBounds(const Tokenizer *tokenizer, const Token *Location, const std::string &what) + { + _writemsg(tokenizer, Location, "error", "" + what + " is out of bounds", "outOfBounds"); + } + static bool outOfBounds() + { + return true; + } + + void stlOutOfBounds(const Tokenizer *tokenizer, const Token *Location, const std::string &what) + { + _writemsg(tokenizer, Location, "error", "" + what + " is out of bounds", "stlOutOfBounds"); + } + static bool stlOutOfBounds() + { + return true; + } + + void noConstructor(const Tokenizer *tokenizer, const Token *Location, const std::string &classname) + { + _writemsg(tokenizer, Location, "style", "The class '" + classname + "' has no constructor", "noConstructor"); + } + static bool noConstructor(const Settings &s) + { + return s._checkCodingStyle; + } + + void uninitVar(const Tokenizer *tokenizer, const Token *Location, const std::string &classname, const std::string &varname) + { + _writemsg(tokenizer, Location, "style", "Member variable not initialized in the constructor '" + classname + "::" + varname + "'", "uninitVar"); + } + static bool uninitVar(const Settings &s) + { + return s._checkCodingStyle; + } + + void unusedPrivateFunction(const Tokenizer *tokenizer, const Token *Location, const std::string &classname, const std::string &funcname) + { + _writemsg(tokenizer, Location, "style", "Unused private function '" + classname + "::" + funcname + "'", "unusedPrivateFunction"); + } + static bool unusedPrivateFunction(const Settings &s) + { + return s._checkCodingStyle; + } + + void memsetClass(const Tokenizer *tokenizer, const Token *Location, const std::string &memfunc) + { + _writemsg(tokenizer, Location, "error", "Using '" + memfunc + "' on class", "memsetClass"); + } + static bool memsetClass() + { + return true; + } + + void memsetStruct(const Tokenizer *tokenizer, const Token *Location, const std::string &memfunc, const std::string &classname) + { + _writemsg(tokenizer, Location, "error", "Using '" + memfunc + "' on struct that contains a 'std::" + classname + "'", "memsetStruct"); + } + static bool memsetStruct() + { + return true; + } + + void operatorEq(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "'operator=' should return something", "operatorEq"); + } + static bool operatorEq(const Settings &s) + { + return s._checkCodingStyle; + } + + void virtualDestructor(const Tokenizer *tokenizer, const Token *Location, const std::string &Base, const std::string &Derived) + { + _writemsg(tokenizer, Location, "error", "Class " + Base + " which is inherited by class " + Derived + " does not have a virtual destructor", "virtualDestructor"); + } + static bool virtualDestructor() + { + return true; + } + + void unusedFunction(const std::string &filename, const std::string &funcname) + { + _writemsg("[" + filename + "]: The function '" + funcname + "' is never used", "unusedFunction"); + } + static bool unusedFunction(const Settings &s) + { + return s._checkCodingStyle || s._showAll; + } + + void mismatchAllocDealloc(const Tokenizer *tokenizer, const std::list &Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Mismatching allocation and deallocation: " + varname + "", "mismatchAllocDealloc"); + } + static bool mismatchAllocDealloc() + { + return true; + } + + void memleak(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Memory leak: " + varname + "", "memleak"); + } + static bool memleak() + { + return true; + } + + void memleakall(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "all", "Memory leak: " + varname + "", "memleakall"); + } + static bool memleakall(const Settings &s) + { + return s._showAll; + } + + void resourceLeak(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Resource leak: " + varname + "", "resourceLeak"); + } + static bool resourceLeak() + { + return true; + } + + void deallocDealloc(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Deallocating a deallocated pointer: " + varname + "", "deallocDealloc"); + } + static bool deallocDealloc() + { + return true; + } + + void deallocuse(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Using '" + varname + "' after it is deallocated / released", "deallocuse"); + } + static bool deallocuse() + { + return true; + } + + void mismatchSize(const Tokenizer *tokenizer, const Token *Location, const std::string &sz) + { + _writemsg(tokenizer, Location, "error", "The given size " + sz + " is mismatching", "mismatchSize"); + } + static bool mismatchSize() + { + return true; + } + + void cstyleCast(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "C-style pointer casting", "cstyleCast"); + } + static bool cstyleCast(const Settings &s) + { + return s._checkCodingStyle; + } + + void redundantIfDelete0(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Redundant condition. It is safe to deallocate a NULL pointer", "redundantIfDelete0"); + } + static bool redundantIfDelete0(const Settings &s) + { + return s._checkCodingStyle; + } + + void redundantIfRemove(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Redundant condition. The remove function in the STL will not do anything if element doesn't exist", "redundantIfRemove"); + } + static bool redundantIfRemove(const Settings &s) + { + return s._checkCodingStyle; + } + + void dangerousUsageStrtol(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "error", "Invalid radix in call to strtol or strtoul. Must be 0 or 2-36", "dangerousUsageStrtol"); + } + static bool dangerousUsageStrtol() + { + return true; + } + + void ifNoAction(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Found redundant if condition - 'if (condition);'", "ifNoAction"); + } + static bool ifNoAction(const Settings &s) + { + return s._checkCodingStyle; + } + + void sprintfOverlappingData(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "error", "Overlapping data buffer " + varname + "", "sprintfOverlappingData"); + } + static bool sprintfOverlappingData() + { + return true; + } + + void udivError(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "error", "Unsigned division. The result will be wrong.", "udivError"); + } + static bool udivError() + { + return true; + } + + void udivWarning(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "all style", "Warning: Division with signed and unsigned operators", "udivWarning"); + } + static bool udivWarning(const Settings &s) + { + return s._checkCodingStyle || s._showAll; + } + + void unusedStructMember(const Tokenizer *tokenizer, const Token *Location, const std::string &structname, const std::string &varname) + { + _writemsg(tokenizer, Location, "style", "struct or union member '" + structname + "::" + varname + "' is never used", "unusedStructMember"); + } + static bool unusedStructMember(const Settings &s) + { + return s._checkCodingStyle; + } + + void passedByValue(const Tokenizer *tokenizer, const Token *Location, const std::string &parname) + { + _writemsg(tokenizer, Location, "style", "Function parameter '" + parname + "' is passed by value. It could be passed by reference instead.", "passedByValue"); + } + static bool passedByValue(const Settings &s) + { + return s._checkCodingStyle; + } + + void constStatement(const Tokenizer *tokenizer, const Token *Location, const std::string &type) + { + _writemsg(tokenizer, Location, "style", "Redundant code: Found a statement that begins with " + type + " constant", "constStatement"); + } + static bool constStatement(const Settings &s) + { + return s._checkCodingStyle; + } + + void charArrayIndex(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Warning - using char variable as array index", "charArrayIndex"); + } + static bool charArrayIndex(const Settings &s) + { + return s._checkCodingStyle; + } + + void charBitOp(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Warning - using char variable in bit operation", "charBitOp"); + } + static bool charBitOp(const Settings &s) + { + return s._checkCodingStyle; + } + + void variableScope(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "never", "The scope of the variable " + varname + " can be limited", "variableScope"); + } + static bool variableScope() + { + return false; + } + + void conditionAlwaysTrueFalse(const Tokenizer *tokenizer, const Token *Location, const std::string &truefalse) + { + _writemsg(tokenizer, Location, "style", "Condition is always " + truefalse + "", "conditionAlwaysTrueFalse"); + } + static bool conditionAlwaysTrueFalse(const Settings &s) + { + return s._checkCodingStyle; + } + + void strPlusChar(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "error", "Unusual pointer arithmetic", "strPlusChar"); + } + static bool strPlusChar() + { + return true; + } + + void returnLocalVariable(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "error", "Returning pointer to local array variable", "returnLocalVariable"); + } + static bool returnLocalVariable() + { + return true; + } + + void dangerousFunctionmktemp(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Found 'mktemp'. You should use 'mkstemp' instead", "dangerousFunctionmktemp"); + } + static bool dangerousFunctionmktemp(const Settings &s) + { + return s._checkCodingStyle; + } + + void dangerousFunctiongets(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Found 'gets'. You should use 'fgets' instead", "dangerousFunctiongets"); + } + static bool dangerousFunctiongets(const Settings &s) + { + return s._checkCodingStyle; + } + + void dangerousFunctionscanf(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "style", "Found 'scanf'. You should use 'fgets' instead", "dangerousFunctionscanf"); + } + static bool dangerousFunctionscanf(const Settings &s) + { + return s._checkCodingStyle; + } + + void iteratorUsage(const Tokenizer *tokenizer, const Token *Location, const std::string &container1, const std::string &container2) + { + _writemsg(tokenizer, Location, "error", "Same iterator is used with both " + container1 + " and " + container2 + "", "iteratorUsage"); + } + static bool iteratorUsage() + { + return true; + } + + void erase(const Tokenizer *tokenizer, const Token *Location) + { + _writemsg(tokenizer, Location, "error", "Dangerous usage of erase", "erase"); + } + static bool erase() + { + return true; + } + + void pushback(const Tokenizer *tokenizer, const Token *Location, const std::string &iterator_name) + { + _writemsg(tokenizer, Location, "error", "After push_back or push_front, the iterator '" + iterator_name + "' may be invalid", "pushback"); + } + static bool pushback() + { + return true; + } + + void unvalidatedInput(const Tokenizer *tokenizer, const Token *Location, const std::string &varname) + { + _writemsg(tokenizer, Location, "all", "Unvalidated input: " + varname + "", "unvalidatedInput"); + } + static bool unvalidatedInput(const Settings &s) + { + return s._showAll; + } + + + static std::string callStackToString(const std::list &callStack); + +private: + void _writemsg(const Tokenizer *tokenizer, const Token *tok, const char severity[], const std::string msg, const std::string &id); + void _writemsg(const Tokenizer *tokenizer, const std::list &callstack, const char severity[], const std::string msg, const std::string &id); + void _writemsg(const std::string msg, const std::string &id); +}; +#endif diff --git a/test/testvalidate.cpp b/test/testvalidate.cpp new file mode 100644 index 000000000..091af32b5 --- /dev/null +++ b/test/testvalidate.cpp @@ -0,0 +1,70 @@ +/* + * 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 TestValidate : public TestFixture +{ +public: + TestValidate() : TestFixture("TestValidate") + { } + +private: + + void run() + { + TEST_CASE(stdin1); + } + + void check(const char code[]) + { + // Tokenize.. + Tokenizer tokenizer; + std::istringstream istr(code); + tokenizer.tokenize(istr, "test.cpp"); + tokenizer.simplifyTokenList(); + + // Clear the error buffer.. + errout.str(""); + + // Check char variable usage.. + CheckValidate checkValidate(&tokenizer, this); + checkValidate.readnum(); + } + + + void stdin1() + { + check("void foo()\n" + "{\n" + " int i;\n" + " std::cin >> i;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (all) Unvalidated input: i\n", errout.str()); + } +}; + +REGISTER_TEST(TestValidate) diff --git a/testrunner.vcproj b/testrunner.vcproj index 571673424..22de0cfdf 100644 --- a/testrunner.vcproj +++ b/testrunner.vcproj @@ -1,7 +1,7 @@  + + @@ -278,6 +282,10 @@ RelativePath=".\src\checkstl.cpp" > + + @@ -390,6 +398,10 @@ RelativePath=".\test\testunusedvar.cpp" > + + diff --git a/tools/errmsg.cpp b/tools/errmsg.cpp index 47e0a6e53..992af1950 100644 --- a/tools/errmsg.cpp +++ b/tools/errmsg.cpp @@ -117,6 +117,10 @@ int main() err.push_back(Message("pushback", Message::error, "After push_back or push_front, the iterator '%1' may be invalid", "iterator_name")); + // checkvalidate.cpp + err.push_back(Message("unvalidatedInput", Message::all, "Unvalidated input: %1", "varname")); + + // Generate code.. std::cout << "Generate code.." << std::endl; std::ofstream fout("errorlogger.h");