diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 5c7e88337..8ac28d243 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -214,6 +214,15 @@ void CheckBufferOverrun::argumentSizeError(const Token *tok, const std::string & reportError(tok, Severity::warning, "argumentSize", "The array '" + varname + "' is too small, the function '" + functionName + "' expects a bigger one."); } +void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token *tok) +{ + reportError(tok, Severity::error, "negativeMemoryAllocationSize", + "Memory allocation size have to be greater or equal to 0.\n" + "Memory allocation size have to be greater or equal to 0." + "The allocation size of memory have to be greater or equal to 0 because" + "negative size have no speficied behaviour."); +} + //--------------------------------------------------------------------------- @@ -1503,6 +1512,9 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() type = tok->strAt(4); var = tok->next()->variable(); nextTok = 8; + if (size < 0) { + negativeMemoryAllocationSizeError(tok->next()->next()); + } } else if (Token::Match(tok, "[*;{}] %var% = new %type% ( %num% )")) { size = 1; type = tok->strAt(4); @@ -1521,6 +1533,10 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() var = tok->next()->variable(); nextTok = 7; + if (size < 0) { + negativeMemoryAllocationSizeError(tok->next()->next()); + } + /** @todo false negatives: this may be too conservative */ if (!var || var->typeEndToken()->str() != "*" || var->typeStartToken()->next() != var->typeEndToken()) continue; @@ -1531,9 +1547,13 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() // malloc() gets count of bytes and not count of // elements, so we should calculate count of elements // manually - unsigned int sizeOfType = _tokenizer->sizeOfType(var->typeStartToken()); - if (sizeOfType > 0) + const unsigned int sizeOfType = _tokenizer->sizeOfType(var->typeStartToken()); + if (sizeOfType > 0) { size /= static_cast(sizeOfType); + } + if (size < 0) { + negativeMemoryAllocationSizeError(tok->next()->next()); + } } else { continue; } diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index ccb1349e3..4d630d1a5 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -218,6 +218,7 @@ private: void bufferOverrunError(const Token *tok, const std::string &varnames = ""); void bufferOverrunError(const std::list &callstack, const std::string &varnames = ""); void strncatUsageError(const Token *tok); + void negativeMemoryAllocationSizeError(const Token *tok); // provide a negative value to memory allocation function 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 terminateStrncpyError(const Token *tok, const std::string &varname); @@ -251,6 +252,7 @@ public: c.possibleReadlinkBufferOverrunError(0, "readlink", "buffer"); c.argumentSizeError(0, "function", "array"); c.writeOutsideBufferSizeError(0,2,3,"write"); + c.negativeMemoryAllocationSizeError(0); } private: diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index b60247f3c..b60903ddc 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -267,6 +267,8 @@ private: TEST_CASE(readlinkat); TEST_CASE(writeOutsideBufferSize) + + TEST_CASE(negativeMemoryAllocationSizeError) // #389 } @@ -4111,6 +4113,40 @@ private: "}"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Writing 1 bytes outside buffer size.\n", "", errout.str()); } + + void negativeMemoryAllocationSizeError() { // #389 + check("void f()\n" + "{\n" + " int *a;\n" + " a = new int[-1];\n" + " delete [] a;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size have to be greater or equal to 0.\n", errout.str()); + + check("void f()\n" + "{\n" + " int *a;\n" + " a = malloc( -10 );\n" + " free(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size have to be greater or equal to 0.\n", errout.str()); + + check("void f()\n" + "{\n" + " int *a;\n" + " a = malloc( -10);\n" + " free(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size have to be greater or equal to 0.\n", errout.str()); + + check("void f()\n" + "{\n" + " int *a;\n" + " a = alloca( -10 );\n" + " free(a);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size have to be greater or equal to 0.\n", errout.str()); + } }; REGISTER_TEST(TestBufferOverrun)