/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2023 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 checkioH #define checkioH //--------------------------------------------------------------------------- #include "check.h" #include "config.h" #include "tokenize.h" #include #include class Function; class Settings; class Token; class Variable; class ErrorLogger; enum class Severity; /// @addtogroup Checks /// @{ /** @brief %Check input output operations. */ class CPPCHECKLIB CheckIO : public Check { friend class TestIO; public: /** @brief This constructor is used when registering CheckIO */ CheckIO() : Check(myName()) {} private: /** @brief This constructor is used when running checks. */ CheckIO(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(myName(), tokenizer, settings, errorLogger) {} /** @brief Run checks on the normal token list */ void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override { CheckIO checkIO(&tokenizer, tokenizer.getSettings(), errorLogger); checkIO.checkWrongPrintfScanfArguments(); checkIO.checkCoutCerrMisusage(); checkIO.checkFileUsage(); checkIO.invalidScanf(); } /** @brief %Check for missusage of std::cout */ void checkCoutCerrMisusage(); /** @brief %Check usage of files*/ void checkFileUsage(); /** @brief scanf can crash if width specifiers are not used */ void invalidScanf(); /** @brief %Checks type and number of arguments given to functions like printf or scanf*/ void checkWrongPrintfScanfArguments(); class ArgumentInfo { public: ArgumentInfo(const Token *arg, const Settings *settings, bool _isCPP); ~ArgumentInfo(); ArgumentInfo(const ArgumentInfo &) = delete; ArgumentInfo& operator= (const ArgumentInfo &) = delete; bool isArrayOrPointer() const; bool isComplexType() const; bool isKnownType() const; bool isStdVectorOrString(); bool isStdContainer(const Token *tok); bool isLibraryType(const Settings *settings) const; const Variable* variableInfo{}; const Token* typeToken{}; const Function* functionInfo{}; Token* tempToken{}; bool element{}; bool _template{}; bool address{}; bool isCPP{}; }; void checkFormatString(const Token * const tok, const Token * const formatStringTok, const Token * argListTok, const bool scan, const bool scanf_s); // Reporting errors.. void coutCerrMisusageError(const Token* tok, const std::string& streamName); void fflushOnInputStreamError(const Token *tok, const std::string &varname); void ioWithoutPositioningError(const Token *tok); void readWriteOnlyFileError(const Token *tok); void writeReadOnlyFileError(const Token *tok); void useClosedFileError(const Token *tok); void seekOnAppendedFileError(const Token *tok); void incompatibleFileOpenError(const Token *tok, const std::string &filename); void invalidScanfError(const Token *tok); void wrongPrintfScanfArgumentsError(const Token* tok, const std::string &functionName, nonneg int numFormat, nonneg int numFunction); void wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName, nonneg int index, nonneg int numFunction); void invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo); void invalidScanfArgTypeError_int(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned); void invalidScanfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_p(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo); void invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo); void invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier); void invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier); static void argumentType(std::ostream & os, const ArgumentInfo * argInfo); static Severity getSeverity(const ArgumentInfo *argInfo); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override { CheckIO c(nullptr, settings, errorLogger); c.coutCerrMisusageError(nullptr, "cout"); c.fflushOnInputStreamError(nullptr, "stdin"); c.ioWithoutPositioningError(nullptr); c.readWriteOnlyFileError(nullptr); c.writeReadOnlyFileError(nullptr); c.useClosedFileError(nullptr); c.seekOnAppendedFileError(nullptr); c.incompatibleFileOpenError(nullptr, "tmp"); c.invalidScanfError(nullptr); c.wrongPrintfScanfArgumentsError(nullptr, "printf",3,2); c.invalidScanfArgTypeError_s(nullptr, 1, "s", nullptr); c.invalidScanfArgTypeError_int(nullptr, 1, "d", nullptr, false); c.invalidScanfArgTypeError_float(nullptr, 1, "f", nullptr); c.invalidPrintfArgTypeError_s(nullptr, 1, nullptr); c.invalidPrintfArgTypeError_n(nullptr, 1, nullptr); c.invalidPrintfArgTypeError_p(nullptr, 1, nullptr); c.invalidPrintfArgTypeError_uint(nullptr, 1, "u", nullptr); c.invalidPrintfArgTypeError_sint(nullptr, 1, "i", nullptr); c.invalidPrintfArgTypeError_float(nullptr, 1, "f", nullptr); c.invalidLengthModifierError(nullptr, 1, "I"); c.invalidScanfFormatWidthError(nullptr, 10, 5, nullptr, "s"); c.invalidScanfFormatWidthError(nullptr, 99, -1, nullptr, "s"); c.wrongPrintfScanfPosixParameterPositionError(nullptr, "printf", 2, 1); } static std::string myName() { return "IO using format string"; } std::string classInfo() const override { return "Check format string input/output operations.\n" "- Bad usage of the function 'sprintf' (overlapping data)\n" "- Missing or wrong width specifiers in 'scanf' format string\n" "- Use a file that has been closed\n" "- File input/output without positioning results in undefined behaviour\n" "- Read to a file that has only been opened for writing (or vice versa)\n" "- Repositioning operation on a file opened in append mode\n" "- The same file can't be open for read and write at the same time on different streams\n" "- Using fflush() on an input stream\n" "- Invalid usage of output stream. For example: 'std::cout << std::cout;'\n" "- Wrong number of arguments given to 'printf' or 'scanf;'\n"; } }; /// @} //--------------------------------------------------------------------------- #endif // checkioH