Skip to content

Commit 5c54e72

Browse files
authored
fix #11542: FP memleak when using memcpy() with pointer (#6792)
1 parent 988c79e commit 5c54e72

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

lib/checkleakautovar.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,40 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
363363
while (Token::Match(ftok, "%name% :: %name%"))
364364
ftok = ftok->tokAt(2);
365365

366+
// bailout for variable passed to library function with out parameter
367+
if (const Library::Function *libFunc = mSettings->library.getFunction(ftok)) {
368+
using ArgumentChecks = Library::ArgumentChecks;
369+
using Direction = ArgumentChecks::Direction;
370+
const std::vector<const Token *> args = getArguments(ftok);
371+
const std::map<int, ArgumentChecks> &argChecks = libFunc->argumentChecks;
372+
bool hasOutParam = std::any_of(argChecks.cbegin(), argChecks.cend(), [](const std::pair<int, ArgumentChecks> &pair) {
373+
return std::any_of(pair.second.direction.cbegin(), pair.second.direction.cend(), [](const Direction dir) {
374+
return dir == Direction::DIR_OUT;
375+
});
376+
});
377+
if (hasOutParam) {
378+
for (int i = 0; i < args.size(); i++) {
379+
if (!argChecks.count(i + 1))
380+
continue;
381+
const ArgumentChecks argCheck = argChecks.at(i + 1);
382+
const bool isInParam = std::any_of(argCheck.direction.cbegin(), argCheck.direction.cend(), [&](const Direction dir) {
383+
return dir == Direction::DIR_IN;
384+
});
385+
if (!isInParam)
386+
continue;
387+
const Token *inTok = args[i];
388+
int indirect = 0;
389+
while (inTok->isUnaryOp("&")) {
390+
inTok = inTok->astOperand1();
391+
indirect++;
392+
}
393+
if (inTok->isVariable() && indirect) {
394+
varInfo.erase(inTok->varId());
395+
}
396+
}
397+
}
398+
}
399+
366400
auto isAssignment = [](const Token* varTok) -> const Token* {
367401
if (varTok->varId()) {
368402
const Token* top = varTok;

test/testleakautovar.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class TestLeakAutoVar : public TestFixture {
6464
TEST_CASE(assign25);
6565
TEST_CASE(assign26);
6666

67+
TEST_CASE(memcpy1); // #11542
68+
TEST_CASE(memcpy2);
69+
6770
TEST_CASE(isAutoDealloc);
6871

6972
TEST_CASE(realloc1);
@@ -635,6 +638,24 @@ class TestLeakAutoVar : public TestFixture {
635638
ASSERT_EQUALS("", errout_str());
636639
}
637640

641+
void memcpy1() { // #11542
642+
const Settings s = settingsBuilder().library("std.cfg").build();
643+
check("void f(char** old, char* value) {\n"
644+
" char *str = strdup(value);\n"
645+
" memcpy(old, &str, sizeof(char*));\n"
646+
"}\n", &s);
647+
ASSERT_EQUALS("", errout_str());
648+
}
649+
650+
void memcpy2() {
651+
const Settings s = settingsBuilder().library("std.cfg").build();
652+
check("void f(char* old, char* value, size_t len) {\n"
653+
" char *str = strdup(value);\n"
654+
" memcpy(old, str, len);\n"
655+
"}\n", &s);
656+
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: str\n", errout_str());
657+
}
658+
638659
void isAutoDealloc() {
639660
check("void f() {\n"
640661
" char *p = new char[100];"

0 commit comments

Comments
 (0)