/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2023 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "checkleakautovar.h"
#include "errortypes.h"
#include "helpers.h"
#include "settings.h"
#include "fixture.h"
#include "tokenize.h"
#include // IWYU pragma: keep
#include
#include
class TestLeakAutoVarStrcpy;
class TestLeakAutoVarWindows;
class TestLeakAutoVar : public TestFixture {
public:
TestLeakAutoVar() : TestFixture("TestLeakAutoVar") {}
private:
Settings settings;
void run() override {
constexpr char xmldata[] = "\n"
"\n"
" \n"
" \n"
" malloc\n"
" realloc\n"
" free\n"
" \n"
" \n"
" socket\n"
" close\n"
" \n"
" \n"
" fopen\n"
" freopen\n"
" fclose\n"
" \n"
" \n"
" \n"
" \n"
" \n"
"";
settings = settingsBuilder(settings).libraryxml(xmldata, sizeof(xmldata)).build();
// Assign
TEST_CASE(assign1);
TEST_CASE(assign2);
TEST_CASE(assign3);
TEST_CASE(assign4);
TEST_CASE(assign5);
TEST_CASE(assign6);
TEST_CASE(assign7);
TEST_CASE(assign8);
TEST_CASE(assign9);
TEST_CASE(assign10);
TEST_CASE(assign11); // #3942: x = a(b(p));
TEST_CASE(assign12); // #4236: FP. bar(&x);
TEST_CASE(assign13); // #4237: FP. char*&ref=p; p=malloc(10); free(ref);
TEST_CASE(assign14);
TEST_CASE(assign15);
TEST_CASE(assign16);
TEST_CASE(assign17); // #9047
TEST_CASE(assign18);
TEST_CASE(assign19);
TEST_CASE(assign20); // #9187
TEST_CASE(assign21); // #10186
TEST_CASE(assign22); // #9139
TEST_CASE(assign23);
TEST_CASE(assign24); // #7440
TEST_CASE(assign25);
TEST_CASE(isAutoDealloc);
TEST_CASE(realloc1);
TEST_CASE(realloc2);
TEST_CASE(realloc3);
TEST_CASE(realloc4);
TEST_CASE(realloc5); // #9292, #9990
TEST_CASE(freopen1);
TEST_CASE(freopen2);
TEST_CASE(deallocuse1);
TEST_CASE(deallocuse3);
TEST_CASE(deallocuse4);
TEST_CASE(deallocuse5); // #4018: FP. free(p), p = 0;
TEST_CASE(deallocuse6); // #4034: FP. x = p = f();
TEST_CASE(deallocuse7); // #6467, #6469, #6473
TEST_CASE(deallocuse8); // #1765
TEST_CASE(deallocuse9); // #9781
TEST_CASE(deallocuse10);
TEST_CASE(deallocuse11); // #8302
TEST_CASE(deallocuse12);
TEST_CASE(deallocuse13);
TEST_CASE(doublefree1);
TEST_CASE(doublefree2);
TEST_CASE(doublefree3); // #4914
TEST_CASE(doublefree4); // #5451 - FP when exit is called
TEST_CASE(doublefree5); // #5522
TEST_CASE(doublefree6); // #7685
TEST_CASE(doublefree7);
TEST_CASE(doublefree8);
TEST_CASE(doublefree9);
TEST_CASE(doublefree10); // #8706
TEST_CASE(doublefree11);
TEST_CASE(doublefree12); // #10502
TEST_CASE(doublefree13); // #11008
TEST_CASE(doublefree14); // #9708
TEST_CASE(doublefree15);
TEST_CASE(doublefree16);
// exit
TEST_CASE(exit1);
TEST_CASE(exit2);
TEST_CASE(exit3);
// handling function calls
TEST_CASE(functioncall1);
// goto
TEST_CASE(goto1);
TEST_CASE(goto2);
TEST_CASE(goto3); // #11431
// if/else
TEST_CASE(ifelse1);
TEST_CASE(ifelse2);
TEST_CASE(ifelse3);
TEST_CASE(ifelse4);
TEST_CASE(ifelse5);
TEST_CASE(ifelse6); // #3370
TEST_CASE(ifelse7); // #5576 - if (fd < 0)
TEST_CASE(ifelse8); // #5747 - if (fd == -1)
TEST_CASE(ifelse9); // #5273 - if (X(p==NULL, 0))
TEST_CASE(ifelse10); // #8794 - if (!(x!=NULL))
TEST_CASE(ifelse11); // #8365 - if (NULL == (p = malloc(4)))
TEST_CASE(ifelse12); // #8340 - if ((*p = malloc(4)) == NULL)
TEST_CASE(ifelse13); // #8392
TEST_CASE(ifelse14); // #9130 - if (x == (char*)NULL)
TEST_CASE(ifelse15); // #9206 - if (global_ptr = malloc(1))
TEST_CASE(ifelse16); // #9635 - if (p = malloc(4), p == NULL)
TEST_CASE(ifelse17); // if (!!(!p))
TEST_CASE(ifelse18);
TEST_CASE(ifelse19);
TEST_CASE(ifelse20); // #10182
TEST_CASE(ifelse21);
TEST_CASE(ifelse22); // #10187
TEST_CASE(ifelse23); // #5473
TEST_CASE(ifelse24); // #1733
TEST_CASE(ifelse25); // #9966
TEST_CASE(ifelse26);
TEST_CASE(ifelse27);
TEST_CASE(ifelse28); // #11038
// switch
TEST_CASE(switch1);
// loops
TEST_CASE(loop1);
TEST_CASE(loop2);
// mismatching allocation/deallocation
TEST_CASE(mismatchAllocDealloc);
TEST_CASE(smartPointerDeleter);
TEST_CASE(smartPointerRelease);
// Execution reaches a 'return'
TEST_CASE(return1);
TEST_CASE(return2);
TEST_CASE(return3);
TEST_CASE(return4);
TEST_CASE(return5);
TEST_CASE(return6); // #8282 return {p, p}
TEST_CASE(return7); // #9343 return (uint8_t*)x
TEST_CASE(return8);
TEST_CASE(return9);
TEST_CASE(return10);
// General tests: variable type, allocation type, etc
TEST_CASE(test1);
TEST_CASE(test2);
TEST_CASE(test3); // #3954 - reference pointer
TEST_CASE(test4); // #5923 - static pointer
TEST_CASE(test5); // unknown type
// Execution reaches a 'throw'
TEST_CASE(throw1);
TEST_CASE(throw2);
// Possible leak => Further configuration is needed for complete analysis
TEST_CASE(configuration1);
TEST_CASE(configuration2);
TEST_CASE(configuration3);
TEST_CASE(configuration4);
TEST_CASE(configuration5);
TEST_CASE(configuration6);
TEST_CASE(ptrptr);
TEST_CASE(nestedAllocation);
TEST_CASE(testKeywords); // #6767
TEST_CASE(inlineFunction); // #3989
TEST_CASE(smartPtrInContainer); // #8262
TEST_CASE(functionCallCastConfig); // #9652
TEST_CASE(functionCallLeakIgnoreConfig); // #7923
}
#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
void check_(const char* file, int line, const char code[], bool cpp = false, const Settings *s = nullptr) {
// Clear the error buffer..
errout.str("");
const Settings settings1 = settingsBuilder(s ? *s : settings).checkLibrary().build();
// Tokenize..
Tokenizer tokenizer(&settings1, this);
std::istringstream istr(code);
ASSERT_LOC(tokenizer.tokenize(istr, cpp ? "test.cpp" : "test.c"), file, line);
// Check for leaks..
runChecks(tokenizer, this);
}
void check_(const char* file, int line, const char code[], const Settings & s) {
// Clear the error buffer..
errout.str("");
const Settings settings0 = settingsBuilder(s).checkLibrary().build();
// Tokenize..
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
// Check for leaks..
runChecks(tokenizer, this);
}
void assign1() {
check("void f() {\n"
" char *p = malloc(10);\n"
" p = NULL;\n"
" free(p);\n"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
}
void assign2() {
check("void f() {\n"
" char *p = malloc(10);\n"
" char *q = p;\n"
" free(q);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign3() {
check("void f() {\n"
" char *p = malloc(10);\n"
" char *q = p + 1;\n"
" free(q - 1);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign4() {
check("void f() {\n"
" char *a = malloc(10);\n"
" a += 10;\n"
" free(a - 10);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign5() {
check("void foo()\n"
"{\n"
" char *p = new char[100];\n"
" list += p;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign6() { // #2806 - FP when there is redundant assignment
check("void foo() {\n"
" char *p = malloc(10);\n"
" p = strcpy(p,q);\n"
" free(p);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign7() {
check("void foo(struct str *d) {\n"
" struct str *p = malloc(10);\n"
" d->p = p;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign8() { // linux list
check("void foo(struct str *d) {\n"
" struct str *p = malloc(10);\n"
" d->p = &p->x;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign9() {
check("void foo() {\n"
" char *p = x();\n"
" free(p);\n"
" p = NULL;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign10() {
check("void foo() {\n"
" char *p;\n"
" if (x) { p = malloc(10); }\n"
" if (!x) { p = NULL; }\n"
" free(p);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void assign11() { // #3942 - FP for x = a(b(p));
check("void f() {\n"
" char *p = malloc(10);\n"
" x = a(b(p));\n"
"}");
ASSERT_EQUALS("[test.c:4]: (information) --check-library: Function b() should have