Fixed #2029 (free invalid address) by reporting previously-unreported errors as "inconclusive"
This commit is contained in:
parent
ca2a6e6054
commit
51d128c918
|
@ -2526,17 +2526,29 @@ void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void CheckOther::checkInvalidFree()
|
void CheckOther::checkInvalidFree()
|
||||||
{
|
{
|
||||||
std::set<unsigned int> allocatedVariables;
|
std::map<unsigned int, bool> allocatedVariables;
|
||||||
for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||||
|
|
||||||
// Keep track of which variables were assigned addresses to newly-allocated memory
|
// Keep track of which variables were assigned addresses to newly-allocated memory
|
||||||
if (Token::Match(tok, "%var% = malloc|g_malloc|new")) {
|
if (Token::Match(tok, "%var% = malloc|g_malloc|new")) {
|
||||||
allocatedVariables.insert(tok->varId());
|
allocatedVariables.insert(std::make_pair(tok->varId(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If these variables assigned new values before being used to free the memory, we can't
|
// If a previously-allocated pointer is incremented or decremented, any subsequent
|
||||||
// say anything about whether the resulting expression is valid
|
// free involving pointer arithmetic may or may not be invalid, so we should only
|
||||||
else if (Token::Match(tok, "%var% =")) {
|
// report an inconclusive result.
|
||||||
|
else if (Token::Match(tok, "%var% = %var% +|-") &&
|
||||||
|
tok->varId() == tok->tokAt(2)->varId() &&
|
||||||
|
allocatedVariables.find(tok->varId()) != allocatedVariables.end()) {
|
||||||
|
if (_settings->inconclusive)
|
||||||
|
allocatedVariables[tok->varId()] = true;
|
||||||
|
else
|
||||||
|
allocatedVariables.erase(tok->varId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a previously-allocated pointer is assigned a completely new value,
|
||||||
|
// we can't know if any subsequent free() on that pointer is valid or not.
|
||||||
|
else if (Token::Match(tok, "%var% = ")) {
|
||||||
allocatedVariables.erase(tok->varId());
|
allocatedVariables.erase(tok->varId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2546,13 +2558,16 @@ void CheckOther::checkInvalidFree()
|
||||||
Token::Match(tok, "delete [ ] ( %any% +|- %any%") ||
|
Token::Match(tok, "delete [ ] ( %any% +|- %any%") ||
|
||||||
Token::Match(tok, "delete %any% +|- %any%")) {
|
Token::Match(tok, "delete %any% +|- %any%")) {
|
||||||
|
|
||||||
int varIdx = tok->strAt(1) == "(" ? 2 :
|
const int varIdx = tok->strAt(1) == "(" ? 2 :
|
||||||
tok->strAt(3) == "(" ? 4 : 1;
|
tok->strAt(3) == "(" ? 4 : 1;
|
||||||
unsigned int var1 = tok->tokAt(varIdx)->varId();
|
const unsigned int var1 = tok->tokAt(varIdx)->varId();
|
||||||
unsigned int var2 = tok->tokAt(varIdx + 2)->varId();
|
const unsigned int var2 = tok->tokAt(varIdx + 2)->varId();
|
||||||
if (allocatedVariables.find(var1) != allocatedVariables.end() ||
|
const std::map<unsigned int, bool>::iterator alloc1 = allocatedVariables.find(var1);
|
||||||
allocatedVariables.find(var2) != allocatedVariables.end()) {
|
const std::map<unsigned int, bool>::iterator alloc2 = allocatedVariables.find(var2);
|
||||||
invalidFreeError(tok);
|
if (alloc1 != allocatedVariables.end()) {
|
||||||
|
invalidFreeError(tok, alloc1->second);
|
||||||
|
} else if (alloc2 != allocatedVariables.end()) {
|
||||||
|
invalidFreeError(tok, alloc2->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2569,9 +2584,9 @@ void CheckOther::checkInvalidFree()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOther::invalidFreeError(const Token *tok)
|
void CheckOther::invalidFreeError(const Token *tok, bool inconclusive)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "invalidFree", "Invalid memory address freed.");
|
reportError(tok, Severity::error, "invalidFree", "Invalid memory address freed.", inconclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ public:
|
||||||
|
|
||||||
/** @brief %Check for free() operations on invalid memory locations */
|
/** @brief %Check for free() operations on invalid memory locations */
|
||||||
void checkInvalidFree();
|
void checkInvalidFree();
|
||||||
void invalidFreeError(const Token *tok);
|
void invalidFreeError(const Token *tok, bool inconclusive);
|
||||||
|
|
||||||
/** @brief %Check for double free or double close operations */
|
/** @brief %Check for double free or double close operations */
|
||||||
void checkDoubleFree();
|
void checkDoubleFree();
|
||||||
|
|
|
@ -6183,15 +6183,6 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Invalid memory address freed.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Invalid memory address freed.\n", errout.str());
|
||||||
|
|
||||||
|
|
||||||
check(
|
|
||||||
"void foo(char *p) {\n"
|
|
||||||
" char *a = new char;\n"
|
|
||||||
" a = a - 10;\n"
|
|
||||||
" delete (a + 10);\n"
|
|
||||||
"}");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
|
|
||||||
check(
|
check(
|
||||||
"void foo(char *p) {\n"
|
"void foo(char *p) {\n"
|
||||||
" char *a = new char;\n"
|
" char *a = new char;\n"
|
||||||
|
@ -6227,6 +6218,23 @@ private:
|
||||||
" delete (a + 10);\n"
|
" delete (a + 10);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Invalid memory address freed.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (error) Invalid memory address freed.\n", errout.str());
|
||||||
|
|
||||||
|
check(
|
||||||
|
"void foo(size_t xx) {\n"
|
||||||
|
" char *ptr = malloc(42);\n"
|
||||||
|
" ptr += xx;\n"
|
||||||
|
" free(ptr - xx - 1);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error, inconclusive) Invalid memory address freed.\n", errout.str());
|
||||||
|
|
||||||
|
check(
|
||||||
|
"void foo(size_t xx) {\n"
|
||||||
|
" char *ptr = malloc(42);\n"
|
||||||
|
" std::cout << ptr;\n"
|
||||||
|
" ptr = otherPtr;\n"
|
||||||
|
" free(ptr - xx - 1);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_redundant_copy(const char code[]) {
|
void check_redundant_copy(const char code[]) {
|
||||||
|
|
Loading…
Reference in New Issue