From f451dd1137bee425d2b704a67caae4b8491dcdef Mon Sep 17 00:00:00 2001 From: Ettl Martin Date: Sun, 17 Feb 2013 17:33:32 +0100 Subject: [PATCH] #3521 implemented new check: wrong buffersize to pipe() function provided. --- lib/checkother.cpp | 45 +++++++++++++++++++++++++++++++++++++++ lib/checkother.h | 7 +++++++ test/testother.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8127efcd1..b79fd9c16 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -523,6 +523,51 @@ void CheckOther::sizeofForNumericParameterError(const Token *tok) " and 'sizeof(char)' can return different results."); } +//--------------------------------------------------------------------------- +// This check detects errors on POSIX systems, when a pipe command called +// with a wrong dimensioned file descriptor array. The pipe command requires +// exactly an integer array of dimension two as parameter. +// +// References: +// - http://linux.die.net/man/2/pipe +// - ticket #3521 +//--------------------------------------------------------------------------- +void CheckOther::checkPipeParameterSize() +{ + if (!_settings->isEnabled("warning") + || !_settings->standards.posix) + return; + + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { + if (Token::Match(tok, "pipe ( %var% )") || + Token::Match(tok, "pipe2 ( %var% ,")) { + const Token * const varTok = tok->tokAt(2); + + const Variable *var = varTok->variable(); + MathLib::bigint dim; + if (var && (var->isArray() || var->isPointer()) && ((dim=var->dimension(0U)) < 2)) { + const std::string strDim = MathLib::longToString(dim); + checkPipeParameterSizeError(varTok,varTok->str(), strDim); + } + } + } + } +} + +void CheckOther::checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim) +{ + reportError(tok, Severity::error, + "wrongPipeParameterSize", "Variable " + strVarName + " must have size 2 when it is used as parameter of pipe() command.\n" + "The pipe()/pipe2() system command takes an argument, which is an array of exactly two integers." + "\nThe variable " + strVarName + " is an array of size " + + strDim + ", which does not match." + ); +} + //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void CheckOther::checkSizeofForArrayParameter() diff --git a/lib/checkother.h b/lib/checkother.h index b67b55850..58de15c45 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -110,6 +110,7 @@ public: checkOther.checkSwitchCaseFallThrough(); checkOther.checkAlwaysTrueOrFalseStringCompare(); checkOther.checkModuloAlwaysTrueFalse(); + checkOther.checkPipeParameterSize(); checkOther.checkAssignBoolToPointer(); checkOther.checkBitwiseOnBoolean(); @@ -297,11 +298,15 @@ public: /** @brief %Check that variadic function calls don't use NULL. If NULL is #defined as 0 and the function expects a pointer, the behaviour is undefined. */ void checkVarFuncNullUB(); + /** @brief %Check that calling the POSIX pipe() system call is called with an integer array of size two. */ + void checkPipeParameterSize(); + private: bool isUnsigned(const Variable *var) const; bool isSigned(const Variable *var) const; // Error messages.. + void checkPipeParameterSizeError(const Token *tok, const std::string &strVarName, const std::string &strDim); void oppositeInnerConditionError(const Token *tok); void clarifyCalculationError(const Token *tok, const std::string &op); void clarifyConditionError(const Token *tok, bool assign, bool boolop); @@ -392,6 +397,7 @@ private: c.doubleFreeError(0, "varname"); c.invalidPointerCastError(0, "float", "double", false); c.negativeBitwiseShiftError(0); + c.checkPipeParameterSizeError(0, "varname", "dimension"); //performance c.redundantCopyError(0, "varname"); @@ -469,6 +475,7 @@ private: "* free() or delete of an invalid memory location\n" "* double free() or double closedir()\n" "* bitwise operation with negative right operand\n" + "* provide wrong dimensioned array to pipe() system command (--std=posix)\n" //performance "* redundant data copying for const variable\n" diff --git a/test/testother.cpp b/test/testother.cpp index 097985859..66742a485 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -194,6 +194,8 @@ private: TEST_CASE(redundantMemWrite); TEST_CASE(varFuncNullUB); + + TEST_CASE(checkPipeParameterSize); // ticket #3521 } void check(const char code[], const char *filename = NULL, bool experimental = false, bool inconclusive = true, bool posix = false) { @@ -6977,6 +6979,56 @@ private: "void b() { a(NULL, 2); }"); ASSERT_EQUALS("", errout.str()); } + + void checkPipeParameterSize() { // #3521 + check("void f(){\n" + "int pipefd[1];\n" //<-- array of two integers is needed + "if (pipe(pipefd) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("[test.cpp:3]: (error) Variable pipefd must have size 2 when it is used as parameter of pipe() command.\n", errout.str()); + + check("void f(){\n" + "int pipefd[2];\n" + "if (pipe(pipefd) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("", errout.str()); + + check("void f(){\n" + "int pipefd[20];\n" + "if (pipe(pipefd) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("", errout.str()); + + check("void f(){\n" + "int pipefd[1];\n" //<-- array of two integers is needed + "if (pipe2(pipefd,0) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("[test.cpp:3]: (error) Variable pipefd must have size 2 when it is used as parameter of pipe() command.\n", errout.str()); + + check("void f(){\n" + "int pipefd[2];\n" + "if (pipe2(pipefd,0) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("", errout.str()); + + check("void f(){\n" + "int pipefd[20];\n" + "if (pipe2(pipefd,0) == -1) {\n" + " return;\n" + " }\n" + "}",NULL,false,false,true); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestOther)