/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2020 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 "library.h"
#include "settings.h"
#include "testsuite.h"
#include "tokenize.h"
#include
#include
#include
class TestLeakAutoVar : public TestFixture {
public:
TestLeakAutoVar() : TestFixture("TestLeakAutoVar") {
}
private:
Settings settings;
void run() OVERRIDE {
int id = 0;
while (!Library::ismemory(++id));
settings.library.setalloc("malloc", id, -1);
settings.library.setrealloc("realloc", id, -1);
settings.library.setdealloc("free", id, 1);
while (!Library::ismemory(++id));
settings.library.setalloc("socket", id, -1);
settings.library.setdealloc("close", id, 1);
while (!Library::isresource(++id));
settings.library.setalloc("fopen", id, -1);
settings.library.setrealloc("freopen", id, -1, 3);
settings.library.setdealloc("fclose", id, 1);
settings.library.smartPointers.insert("std::shared_ptr");
settings.library.smartPointers.insert("std::unique_ptr");
const char xmldata[] = "\n"
"\n"
" \n"
"";
tinyxml2::XMLDocument doc;
doc.Parse(xmldata, sizeof(xmldata));
settings.library.load(doc);
// 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);
// TODO 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(isAutoDealloc);
TEST_CASE(realloc1);
TEST_CASE(realloc2);
TEST_CASE(realloc3);
TEST_CASE(freopen1);
TEST_CASE(freopen2);
TEST_CASE(deallocuse1);
TEST_CASE(deallocuse2);
TEST_CASE(deallocuse3);
TEST_CASE(deallocuse4);
// TODO 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(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
// exit
TEST_CASE(exit1);
TEST_CASE(exit2);
TEST_CASE(exit3);
// handling function calls
TEST_CASE(functioncall1);
// goto
TEST_CASE(goto1);
TEST_CASE(goto2);
// 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))
// switch
TEST_CASE(switch1);
// loops
TEST_CASE(loop1);
// 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);
// 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(ptrptr);
TEST_CASE(nestedAllocation);
TEST_CASE(testKeywords); // #6767
TEST_CASE(inlineFunction); // #3989
TEST_CASE(smartPtrInContainer); // #8262
TEST_CASE(recursiveCountLimit); // #5872 #6157 #9097
TEST_CASE(functionCallCastConfig); // #9652
}
void check(const char code[], bool cpp = false) {
// Clear the error buffer..
errout.str("");
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, cpp?"test.cpp":"test.c");
// Check for leaks..
CheckLeakAutoVar c;
settings.checkLibrary = true;
settings.addEnabled("information");
c.runChecks(&tokenizer, &settings, this);
}
void check(const char code[], Settings & settings) {
// Clear the error buffer..
errout.str("");
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// Check for leaks..
CheckLeakAutoVar c;
settings.checkLibrary = true;
settings.addEnabled("information");
c.runChecks(&tokenizer, &settings, this);
}
void checkP(const char code[], bool cpp = false) {
// Clear the error buffer..
errout.str("");
// Raw tokens..
std::vector files(1, cpp?"test.cpp":"test.c");
std::istringstream istr(code);
const simplecpp::TokenList tokens1(istr, files, files[0]);
// Preprocess..
simplecpp::TokenList tokens2(files);
std::map filedata;
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
// Tokenizer..
Tokenizer tokenizer(&settings, this);
tokenizer.createTokens(std::move(tokens2));
tokenizer.simplifyTokens1("");
// Check for leaks..
CheckLeakAutoVar c;
settings.checkLibrary = true;
settings.addEnabled("information");
c.runChecks(&tokenizer, &settings, 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