From a117b8dd1af325a89cc1fce6849006cb277267d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Wed, 11 Sep 2024 09:20:28 +0200 Subject: [PATCH] fix #11542 and add tests --- lib/checkleakautovar.cpp | 40 ++++++++++++++++++++++++++++++---------- test/testleakautovar.cpp | 23 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index dc18e125ee3..5370b1b8811 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -372,23 +372,43 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token *dst = args[0]; const Token *src = args[1]; - // check that arguments are pointers - bool dstIsPtr = dst->isVariable() && dst->variable()->isPointer(); - if (!dstIsPtr && dst->str() == "&") { + // check that dst arg is pointer to pointer + int dstIndirectionLevel = 0; + while (dst->str() == "*") { dst = dst->astOperand1(); - dstIsPtr = true; + dstIndirectionLevel--; } - bool srcIsPtr = src->isVariable() && src->variable()->isPointer(); - if (!srcIsPtr && src->str() == "&") { + if (dst->str() == "&") { + dst = dst->astOperand1(); + dstIndirectionLevel++; + } + if (!dst->isVariable()) + continue; + if (dstIndirectionLevel + dst->variable()->valueType()->pointer != 2) + continue; + + // check that src arg is pointer to pointer + int srcIndirectionLevel = 0; + while (src->str() == "*") { src = src->astOperand1(); - srcIsPtr = true; + srcIndirectionLevel--; } - if (!dstIsPtr || !srcIsPtr) { + if (src->str() == "&") { + src = src->astOperand1(); + srcIndirectionLevel++; + } + if (!src->isVariable()) continue; + if (srcIndirectionLevel + src->variable()->valueType()->pointer != 2) + continue; + + if (!dst->variable()->isArgument()) { + varInfo.alloctype[dst->varId()].status = VarInfo::AllocStatus::ALLOC; } - // TODO: check that dst and src are pointers to pointers - // TODO: move ownership from src to dst + // no multivariable checking currently (see assignment below) + // treat source pointer as unallocated + varInfo.erase(src->varId()); } auto isAssignment = [](const Token* varTok) -> const Token* { diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 3c86d7568f8..d145a59b695 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -64,6 +64,9 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(assign25); TEST_CASE(assign26); + TEST_CASE(memcpyWithPtr1); // #11542 + TEST_CASE(memcpyWithPtr2); + TEST_CASE(isAutoDealloc); TEST_CASE(realloc1); @@ -631,6 +634,26 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("", errout_str()); } + void memcpyWithPtr1() { // #11542 + check("#include \n" + "void f(char** old, char* value) {\n" + " char *str = strdup(value);\n" + " memcpy(old, &str, sizeof(char*));\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } + + void memcpyWithPtr2() { + check("#include \n" + "void f(char* value) {\n" + " char *old = NULL;\n" + " char *str = strdup(value);\n" + " memcpy(&old, &str, sizeof(char*));\n" + "}\n"); + // TODO: make this fail + ASSERT_EQUALS("", errout_str()); + } + void isAutoDealloc() { check("void f() {\n" " char *p = new char[100];"