/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2016 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 "tokenize.h"
#include "checkleakautovar.h"
#include "testsuite.h"
class TestLeakAutoVar : public TestFixture {
public:
TestLeakAutoVar() : TestFixture("TestLeakAutoVar") {
}
private:
Settings settings;
void run() {
int id = 0;
while (!settings.library.ismemory(++id));
settings.library.setalloc("malloc", id);
settings.library.setdealloc("free", id);
while (!settings.library.isresource(++id));
settings.library.setalloc("fopen", id);
settings.library.setdealloc("fclose", id);
// 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(deallocuse1);
TEST_CASE(deallocuse2);
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(doublefree1);
TEST_CASE(doublefree2);
TEST_CASE(doublefree3); // #4914
TEST_CASE(doublefree4); // #5451 - FP when exit is called
// exit
TEST_CASE(exit1);
TEST_CASE(exit2);
// 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)
// switch
TEST_CASE(switch1);
// loops
TEST_CASE(loop1);
// mismatching allocation/deallocation
TEST_CASE(mismatch_fopen_free);
// Execution reaches a 'return'
TEST_CASE(return1);
TEST_CASE(return2);
TEST_CASE(return3);
TEST_CASE(return4);
// 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
}
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");
tokenizer.simplifyTokenList2();
// Check for leaks..
CheckLeakAutoVar c;
settings.checkLibrary = true;
settings.addEnabled("information");
c.runSimplifiedChecks(&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