Fix #9343 (memleak FP when return with cast) (#2162)

This was most likely introduced when the checks were changed to run on
the full tokenlist instead of the simplified one.

Take care to warn about cases where casts destroy the pointer, such as

	uint8_t f() {
		void* x = malloc(1);
		return (uint8_t)x;
	}
This commit is contained in:
Rikard Falkeborn 2019-09-20 15:09:27 +02:00 committed by Daniel Marjamäki
parent 049f6475ee
commit 007b5d3e8d
2 changed files with 57 additions and 6 deletions

View File

@ -930,13 +930,21 @@ void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
if (var) {
bool used = false;
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
if (tok2->str() == ";")
if (tok2->str() == ";" || Token::simpleMatch(tok2, "return ;"))
break;
if (Token::Match(tok2, "return|(|{|, %varid% [});,]", varid)) {
used = true;
break;
}
if (Token::Match(tok2, "return|(|{|, & %varid% . %name% [});,]", varid)) {
if (!Token::Match(tok2, "return|(|{|,"))
continue;
tok2 = tok2->next();
while (tok2 && tok2->isCast() && (tok2->valueType()->pointer || (tok2->valueType()->typeSize(*mSettings) >= mSettings->sizeof_pointer)))
tok2 = tok2->astOperand2() ? tok2->astOperand2() : tok2->astOperand1();
if (Token::Match(tok2, "%varid%", varid))
tok2 = tok2->next();
else if (Token::Match(tok2, "& %varid% . %name%", varid))
tok2 = tok2->tokAt(4);
else
continue;
if (Token::Match(tok2, "[});,]")) {
used = true;
break;
}

View File

@ -144,6 +144,7 @@ private:
TEST_CASE(return4);
TEST_CASE(return5);
TEST_CASE(return6); // #8282 return {p, p}
TEST_CASE(return7); // #9343 return (uint8_t*)x
// General tests: variable type, allocation type, etc
TEST_CASE(test1);
@ -521,6 +522,16 @@ private:
" return p;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f(void* p) {\n"
" if (a) {\n"
" free(p);\n"
" return;\n"
" }\n"
" g(p);\n"
" return;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void deallocuse5() { // #4018
@ -1694,6 +1705,38 @@ private:
ASSERT_EQUALS("", errout.str());
}
void return7() { // #9343
check("uint8_t *f() {\n"
" void *x = malloc(1);\n"
" return (uint8_t *)x;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("uint8_t f() {\n"
" void *x = malloc(1);\n"
" return (uint8_t)x;\n"
"}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str());
check("void** f() {\n"
" void *x = malloc(1);\n"
" return (void**)x;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void* f() {\n"
" void *x = malloc(1);\n"
" return (long long)x;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void* f() {\n"
" void *x = malloc(1);\n"
" return (void*)(short)x;\n"
"}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str());
}
void test1() { // 3809
check("void f(double*&p) {\n"
" p = malloc(0x100);\n"