* Fix 9298

Tell cppcheck that strcpy returns its first argument, and use that
knowledge in checkTokenInsideExpression.

* Add missing unit tests in cmake
This commit is contained in:
Ken-Patrick Lehrmann 2020-01-09 08:47:36 +01:00 committed by Daniel Marjamäki
parent bca5d0d820
commit 0b7649ca9b
4 changed files with 74 additions and 4 deletions

View File

@ -4641,7 +4641,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
</function>
<!-- char *strcpy(char *desstr, const char *srcstr); -->
<function name="strcpy,std::strcpy">
<returnValue type="char *"/>
<returnValue type="char *">arg1</returnValue>
<noreturn>false</noreturn>
<leak-ignore/>
<arg nr="1" direction="out">

View File

@ -743,8 +743,31 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
deallocUseError(tok, tok->str());
} else if (Token::simpleMatch(tok->tokAt(-2), "= &")) {
varInfo->erase(tok->varId());
} else if (Token::Match(tok->previous(), "= %var% [;,)]")) {
varInfo->erase(tok->varId());
} else {
// check if tok is assigned into another variable
const Token *rhs = tok;
while (rhs->astParent()) {
if (rhs->astParent()->str() == "=")
break;
rhs = rhs->astParent();
}
if (rhs->varId() == tok->varId()) {
// simple assignment
varInfo->erase(tok->varId());
} else if (rhs->str() == "(" && mSettings->library.returnValue(rhs->astOperand1()) != emptyString) {
// #9298, assignment through return value of a function
const std::string &returnValue = mSettings->library.returnValue(rhs->astOperand1());
if (returnValue.compare(0, 3, "arg") == 0) {
int argn;
const Token *func = getTokenArgumentFunction(tok, argn);
if (func) {
const std::string arg = "arg" + std::to_string(argn + 1);
if (returnValue == arg) {
varInfo->erase(tok->varId());
}
}
}
}
}
} else if (Token::Match(tok->previous(), "& %name% = %var% ;")) {
varInfo->referenced.insert(tok->tokAt(2)->varId());
@ -759,7 +782,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
if (alloc.type == 0)
alloc.status = VarInfo::NOALLOC;
functionCall(tok, openingPar, varInfo, alloc, nullptr);
return openingPar->link();
return openingPar;
}
return nullptr;

View File

@ -59,6 +59,12 @@ if (BUILD_TESTS)
add_fixture(${CMAKE_MATCH_1})
endif()
endforeach()
add_fixture("TestLeakAutoVarStrcpy")
add_fixture("TestLeakAutoVarWindows")
add_fixture("TestMemleakInFunction")
add_fixture("TestMemleakInClass")
add_fixture("TestMemleakStructMember")
add_fixture("TestMemleakNoVar")
function(add_cfg CFG_TEST)
set(options INCONCLUSIVE)

View File

@ -2020,7 +2020,48 @@ private:
REGISTER_TEST(TestLeakAutoVar)
class TestLeakAutoVarStrcpy: public TestFixture {
public:
TestLeakAutoVarStrcpy() : TestFixture("TestLeakAutoVarStrcpy") {
}
private:
Settings settings;
void check(const char code[]) {
// Clear the error buffer..
errout.str("");
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// Check for leaks..
CheckLeakAutoVar checkLeak;
settings.checkLibrary = true;
settings.addEnabled("information");
checkLeak.runChecks(&tokenizer, &settings, this);
}
void run() OVERRIDE {
LOAD_LIB_2(settings.library, "std.cfg");
TEST_CASE(returnedValue); // #9298
}
void returnedValue() { // #9298
check("char *m;\n"
"void strcpy_returnedvalue(const char* str)\n"
"{\n"
" char* ptr = new char[strlen(str)+1];\n"
" m = strcpy(ptr, str);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
};
REGISTER_TEST(TestLeakAutoVarStrcpy)
class TestLeakAutoVarWindows : public TestFixture {