New check: negative size in array declaration. Ticket #1760

This commit is contained in:
Daniel Marjamäki 2015-05-03 15:00:47 +02:00
parent e837bad01d
commit baa1ae079d
3 changed files with 44 additions and 4 deletions

View File

@ -970,6 +970,33 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo
} }
} }
//---------------------------------------------------------------------------
// Negative size in array declarations
//---------------------------------------------------------------------------
void CheckBufferOverrun::negativeArraySize()
{
const SymbolDatabase* symbolDatabase = _tokenizer->getSymbolDatabase();
for (unsigned int i = 1; i <= _tokenizer->varIdCount(); i++) {
const Variable * const var = symbolDatabase->getVariableFromVarId(i);
if (!var || !var->isArray())
continue;
const Token * const nameToken = var->nameToken();
if (!Token::Match(nameToken, "%var% [") || !nameToken->next()->astOperand2())
continue;
const ValueFlow::Value *sz = nameToken->next()->astOperand2()->getValueLE(-1,_settings);
if (!sz)
continue;
negativeArraySizeError(nameToken);
}
}
void CheckBufferOverrun::negativeArraySizeError(const Token *tok)
{
reportError(tok, Severity::error, "negativeArraySize",
"Declaration of array '" + (tok ? tok->str() : std::string()) + "' with negative size is undefined behaviour");
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Checking member variables of structs. // Checking member variables of structs.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -60,6 +60,7 @@ public:
checkBufferOverrun.bufferOverrun(); checkBufferOverrun.bufferOverrun();
checkBufferOverrun.bufferOverrun2(); checkBufferOverrun.bufferOverrun2();
checkBufferOverrun.arrayIndexThenCheck(); checkBufferOverrun.arrayIndexThenCheck();
checkBufferOverrun.negativeArraySize();
} }
/** @brief %Check for buffer overruns */ /** @brief %Check for buffer overruns */
@ -71,6 +72,9 @@ public:
/** @brief Using array index before bounds check */ /** @brief Using array index before bounds check */
void arrayIndexThenCheck(); void arrayIndexThenCheck();
/** @brief negative size for array */
void negativeArraySize();
/** @brief %Check for buffer overruns by inspecting execution paths */ /** @brief %Check for buffer overruns by inspecting execution paths */
void executionPaths(); void executionPaths();
@ -218,6 +222,7 @@ private:
void bufferOverrunError(const std::list<const Token *> &callstack, const std::string &varnames = emptyString); void bufferOverrunError(const std::list<const Token *> &callstack, const std::string &varnames = emptyString);
void strncatUsageError(const Token *tok); void strncatUsageError(const Token *tok);
void negativeMemoryAllocationSizeError(const Token *tok); // provide a negative value to memory allocation function void negativeMemoryAllocationSizeError(const Token *tok); // provide a negative value to memory allocation function
void negativeArraySizeError(const Token *tok);
void outOfBoundsError(const Token *tok, const std::string &what, const bool show_size_info, const MathLib::bigint &supplied_size, const MathLib::bigint &actual_size); void outOfBoundsError(const Token *tok, const std::string &what, const bool show_size_info, const MathLib::bigint &supplied_size, const MathLib::bigint &actual_size);
void sizeArgumentAsCharError(const Token *tok); void sizeArgumentAsCharError(const Token *tok);
void terminateStrncpyError(const Token *tok, const std::string &varname); void terminateStrncpyError(const Token *tok, const std::string &varname);
@ -251,6 +256,7 @@ public:
c.possibleBufferOverrunError(0, "source", "destination", false); c.possibleBufferOverrunError(0, "source", "destination", false);
c.argumentSizeError(0, "function", "array"); c.argumentSizeError(0, "function", "array");
c.negativeMemoryAllocationSizeError(0); c.negativeMemoryAllocationSizeError(0);
c.negativeArraySizeError(0);
c.reportError(nullptr, Severity::warning, "arrayIndexOutOfBoundsCond", "Array 'x[10]' accessed at index 20, which is out of bounds. Otherwise condition 'y==20' is redundant."); c.reportError(nullptr, Severity::warning, "arrayIndexOutOfBoundsCond", "Array 'x[10]' accessed at index 20, which is out of bounds. Otherwise condition 'y==20' is redundant.");
} }
private: private:

View File

@ -60,10 +60,8 @@ private:
} }
// Check for buffer overruns.. // Check for buffer overruns..
CheckBufferOverrun checkBufferOverrun(&tokenizer, &settings, this); CheckBufferOverrun checkBufferOverrun;
checkBufferOverrun.bufferOverrun(); checkBufferOverrun.runSimplifiedChecks(&tokenizer, &settings, this);
checkBufferOverrun.bufferOverrun2();
checkBufferOverrun.arrayIndexThenCheck();
} }
void check(const char code[], const Settings &settings, const char filename[] = "test.cpp") { void check(const char code[], const Settings &settings, const char filename[] = "test.cpp") {
@ -246,6 +244,7 @@ private:
TEST_CASE(bufferNotZeroTerminated); TEST_CASE(bufferNotZeroTerminated);
TEST_CASE(negativeMemoryAllocationSizeError) // #389 TEST_CASE(negativeMemoryAllocationSizeError) // #389
TEST_CASE(negativeArraySize);
TEST_CASE(garbage1) // #6303 TEST_CASE(garbage1) // #6303
} }
@ -3806,6 +3805,14 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str());
} }
void negativeArraySize() {
check("void f(int sz) {\n" // #1760 - VLA
" int a[sz];\n"
"}\n"
"void x() { f(-100); }");
ASSERT_EQUALS("[test.cpp:2]: (error) Declaration of array 'a' with negative size is undefined behaviour\n", errout.str());
}
void garbage1() { void garbage1() {
check("void foo() {\n" check("void foo() {\n"
"char *a = malloc(10);\n" "char *a = malloc(10);\n"