CheckMemoryLeak: Cleanup the old memory leaks check

This commit is contained in:
Daniel Marjamäki 2018-12-17 18:12:50 +01:00
parent f118c22bb6
commit 3b328f9187
3 changed files with 6 additions and 2301 deletions

File diff suppressed because it is too large Load Diff

View File

@ -187,95 +187,16 @@ public:
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) override {
CheckMemoryLeakInFunction checkMemoryLeak(tokenizer, settings, errorLogger);
checkMemoryLeak.checkReallocUsage();
// Commented out so we can evaluate if this checking can be removed.
//checkMemoryLeak.check();
}
/** @brief Unit testing : testing the white list */
static bool test_white_list(const std::string &funcname, const Settings *settings, bool cpp);
/** @brief Perform checking */
void check();
/**
* Checking for a memory leak caused by improper realloc usage.
*/
void checkReallocUsage();
/**
* Inspect a function call. the call_func and getcode are recursive
* @param tok token where the function call occurs
* @param callstack callstack
* @param varid variable id to check
* @param alloctype if memory is allocated, this indicates the type of allocation
* @param dealloctype if memory is deallocated, this indicates the type of deallocation
* @param allocpar if function allocates varid parameter
* @param sz not used by call_func - see getcode
* @return These are the possible return values:
* - NULL : no significant code
* - "recursive" : recursive function
* - "alloc" : the function returns allocated memory
* - "dealloc" : the function deallocates the variable
* - "dealloc_"
* - "use" : the variable is used (unknown usage of the variable => the checking bails out)
* - "callfunc" : a function call with unknown side effects
* - "&use"
*/
const char * call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz);
/**
* Extract a new tokens list that is easier to parse than the "mTokenizer->tokens()", the
* extracted tokens list describes how the given variable is used.
* The getcode and call_func are recursive
* @param tok start parse token
* @param callstack callstack
* @param varid variable id
* @param alloctype keep track of what type of allocation is used
* @param dealloctype keeps track of what type of deallocation is used
* @param classmember should be set if the inspected function is a class member
* @param sz size of type, used to check for mismatching size of allocation. for example "int *a;" => the sz is "sizeof(int)"
* @return Newly allocated token array. Caller needs to release reserved
* memory by calling TokenList::deleteTokens(returnValue);
* Returned tokens:
* - "alloc" : the variable is allocated
* - "assign" : the variable is assigned a new value
* - "break" : corresponds to "break"
* - "callfunc" : a function call with unknown side effects
* - "continue" : corresponds to "continue"
* - "dealloc" : the variable is deallocated
* - "goto" : corresponds to a "goto"
* - "if" : there is an "if"
* - "if(var)" : corresponds with "if ( var != 0 )"
* - "if(!var)" : corresponds with "if ( var == 0 )"
* - "ifv" : the variable is used in some way in a "if"
* - "loop" : corresponds to either a "for" or a "while"
* - "realloc" : the variable is reallocated
* - "return" : corresponds to a "return"
* - "use" : unknown usage -> bail out checking of this execution path
* - "&use" : the address of the variable is taken
* - "::use" : calling member function of class
* - "use_" : content of variable is accessed (used to warn access after dealloc)
*/
Token *getcode(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool classmember, unsigned int sz);
/**
* Simplify code e.g. by replacing empty "{ }" with ";"
* @param tok first token. The tokens list can be modified.
*/
void simplifycode(Token *tok) const;
static const Token *findleak(const Token *tokens);
/**
* Checking the variable varname
* @param startTok start token
* @param varname name of variable (for error messages)
* @param varid variable id
* @param classmember is the scope inside a class member function
* @param sz size of type.. if the variable is a "int *" then sz should be "sizeof(int)"
*/
void checkScope(const Token *startTok, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
private:
/** Report all possible errors (for the --errorlist) */
void getErrorMessages(ErrorLogger *e, const Settings *settings) const override {

View File

@ -149,7 +149,6 @@ private:
// Check for memory leaks..
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, settings, this);
checkMemoryLeak.checkReallocUsage();
checkMemoryLeak.check();
}
@ -158,18 +157,7 @@ private:
LOAD_LIB_2(settings1.library, "posix.cfg");
LOAD_LIB_2(settings2.library, "std.cfg");
// Check that getcode works correctly..
TEST_CASE(testgetcode);
// check that call_func works correctly..
TEST_CASE(call_func);
// Check that simplifycode works correctly..
TEST_CASE(simplifycode);
// Check that errors are found..
TEST_CASE(findleak);
/*
TEST_CASE(simple5);
TEST_CASE(simple7);
TEST_CASE(simple9); // Bug 2435468 - member function "free"
@ -277,7 +265,6 @@ private:
TEST_CASE(realloc3);
TEST_CASE(realloc4);
TEST_CASE(realloc5);
TEST_CASE(realloc6);
TEST_CASE(realloc7);
TEST_CASE(realloc8);
TEST_CASE(realloc9);
@ -382,551 +369,7 @@ private:
TEST_CASE(crash);
TEST_CASE(trac7680);
TEST_CASE(trac7440);
}
std::string getcode(const char code[], const char varname[], bool classfunc=false) {
// Clear the error buffer..
errout.str("");
settings2.standards.posix = true;
// Tokenize..
Tokenizer tokenizer(&settings2, this);
std::istringstream istr(code);
if (!tokenizer.tokenize(istr, "test.cpp"))
return "";
tokenizer.simplifyTokenList2();
const Token * start = tokenizer.tokens();
const SymbolDatabase * db = tokenizer.getSymbolDatabase();
if (db && db->functionScopes.size())
start = db->functionScopes[0]->bodyStart->next();
const unsigned int varId(Token::findmatch(start, varname)->varId());
// getcode..
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings2, nullptr);
std::list<const Token *> callstack(1, nullptr);
CheckMemoryLeak::AllocType allocType, deallocType;
allocType = deallocType = CheckMemoryLeak::No;
Token *tokens = checkMemoryLeak.getcode(start, callstack, varId, allocType, deallocType, classfunc, 1);
// stringify..
std::ostringstream ret;
for (const Token *tok = tokens; tok; tok = tok->next())
ret << tok->str();
TokenList::deleteTokens(tokens);
return ret.str();
}
void testgetcode() {
// alloc;
ASSERT_EQUALS(";;alloc;", getcode("int *a = malloc(100);", "a"));
TODO_ASSERT_EQUALS(";;alloc;", ";;alloccallfunc;", getcode("int *a = ::malloc(100);", "a"));
ASSERT_EQUALS(";;alloc;", getcode("int *a = new int;", "a"));
ASSERT_EQUALS(";;alloc;", getcode("int *a = new int[10];", "a"));
ASSERT_EQUALS(";;alloc;", getcode("int **a = new int*[10];", "a"));
ASSERT_EQUALS(";;alloc;", getcode("int * const a = new int[10];", "a"));
ASSERT_EQUALS(";;alloc;", getcode("const int * const a = new int[10];", "a"));
ASSERT_EQUALS(";;assign;", getcode("A * a = new (X) A;", "a"));
ASSERT_EQUALS(";;alloc;", getcode("int i = open(a,b);", "i"));
ASSERT_EQUALS(";;assign;", getcode("int i = open();", "i"));
ASSERT_EQUALS(";;alloc;use;", getcode("int *p; dostuff(p = new int);", "p"));
ASSERT_EQUALS(";;alloc;use;", getcode("int *p; dostuff(p = new int());", "p"));
ASSERT_EQUALS(";;alloc;use;", getcode("int *p; fred.dostuff(p = new int);", "p"));
ASSERT_EQUALS(";;alloc;use;", getcode("int *p; fred.dostuff(p = new int());", "p"));
// alloc; return use;
ASSERT_EQUALS(";;alloc;returnuse;", getcode("int *a = new int[10]; return a;", "a"));
ASSERT_EQUALS(";;alloc;returnuse;", getcode("char *a = new char[100]; return (char *)a;", "a"));
// alloc; return;
ASSERT_EQUALS(";;alloc;return;", getcode("char *s = new char[100]; return 0;", "s"));
ASSERT_EQUALS(";;alloc;return;", getcode("char *s = new char[100]; return s[0];", "s"));
ASSERT_EQUALS(";;alloc;return;", getcode("char *s = new char[100]; return strcmp(s,x);", "s"));
// lock/unlock..
ASSERT_EQUALS(";;alloc;", getcode("int a; __cppcheck_lock();", ""));
ASSERT_EQUALS(";;callfunc;", getcode("int a; __cppcheck_lock();", "a"));
ASSERT_EQUALS(";;dealloc;", getcode("int a; __cppcheck_unlock();", ""));
ASSERT_EQUALS(";;callfunc;", getcode("int a; __cppcheck_unlock();", "a"));
// dealloc;
ASSERT_EQUALS(";;dealloc;", getcode("char *s; free(s);", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; free((void *)s);", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; free((void *)(s));", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; free(reinterpret_cast<void *>(s));", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; ::free(s);", "s")); // #2802
ASSERT_EQUALS(";;dealloc;", getcode("char *s; delete s;", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; delete (s);", "s"));
TODO_ASSERT_EQUALS(";;dealloc;",
";;;", getcode("char *s; delete (void *)(s);", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; delete [] s;", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; delete [] (s);", "s"));
ASSERT_EQUALS(";;dealloc;", getcode("void *p; foo(fclose(p));", "p"));
ASSERT_EQUALS(";;dealloc;", getcode("void *p; foo(close(p));", "p"));
ASSERT_EQUALS(";;;;", getcode("FILE *f1; FILE *f2; fclose(f1);", "f2"));
ASSERT_EQUALS(";;returnuse;", getcode("FILE *f; return fclose(f) == EOF ? 1 : 2;", "f"));
ASSERT_EQUALS(";;dealloc;", getcode("char *s; s ? free(s) : 0;", "s"));
// if..
ASSERT_EQUALS(";;if{}", getcode("char *s; if (a) { }", "s"));
ASSERT_EQUALS(";;dealloc;ifv{}", getcode("FILE *f; if (fclose(f)) { }", "f"));
ASSERT_EQUALS(";;if(!var){}else{}", getcode("char *s; if (!s) { } else { }", "s"));
TODO_ASSERT_EQUALS(";;ifv{}",";;if{}", getcode("char *s; if (a && s) { }", "s"));
ASSERT_EQUALS(";;ifv{}", getcode("char *s; if (s && a) { }", "s"));
ASSERT_EQUALS(";;;ifv{}", getcode("char *s; int a; if (a && s) { }", "s"));
ASSERT_EQUALS(";;;ifv{}", getcode("char *s; int a; if (s && a) { }", "s"));
ASSERT_EQUALS(";;ifv{}", getcode("char *s; if (a || s) { }", "s"));
ASSERT_EQUALS(";;ifv{}", getcode("char *s; if (s || a) { }", "s"));
ASSERT_EQUALS(";;if(!var){}", getcode("char *s; if (a && !s) { }", "s"));
ASSERT_EQUALS(";;ifv{}", getcode("char *s; if (foo(!s)) { }", "s"));
ASSERT_EQUALS(";;;if{dealloc;};if{dealloc;return;}assign;returnuse;", getcode("char *buf, *tmp; tmp = realloc(buf, 40); if (!(tmp)) { free(buf); return; } buf = tmp; return buf;", "buf"));
ASSERT_EQUALS(";;if{}", getcode("FILE *f; if (fgets(buf,100,f)){}", "f"));
ASSERT_EQUALS(";;alloc;if(var){dealloc;}", getcode("int fd = open(a,b); if (0 < fd) { close(fd); }", "fd"));
ASSERT_EQUALS(";;use;if{}", getcode("char *s; if (x(s)) { }", "s"));
ASSERT_EQUALS(";;use;if{}", getcode("char *s; if (x(&s)) { }", "s"));
ASSERT_EQUALS(";;use;if{}", getcode("char *s; if (!s || x(&s)) { }", "s"));
ASSERT_EQUALS(";;ifv{}", getcode("int ffd; if (ffd<0 && (ffd=a)<0){}", "ffd"));
// if (ticket #2442)
ASSERT_EQUALS(";;;;if(!var){;}ifv{}", getcode("char *s; int x = 0; if (!s) { x = 2; } if (x) { }", "s"));
ASSERT_EQUALS(";;;;if(!var){;}if{}", getcode("char *s; int x = 0; if (!s) { x = 2; } if (y) { }", "s"));
// switch..
ASSERT_EQUALS(";;switch{case;;break;};", getcode("char *s; switch(a){case 1: break;};", "s"));
// loop..
ASSERT_EQUALS(";;loop{}", getcode("char *s; while (a) { }", "s"));
ASSERT_EQUALS(";;loopcallfunc{}", getcode("char *s; while (a()) { }", "s"));
ASSERT_EQUALS(";;loop{}", getcode("char *s; for (a;b;c) { }", "s"));
ASSERT_EQUALS(";;loop{alloc;}", getcode("char *s; for (a;b;c) { s=malloc(10); }", "s"));
ASSERT_EQUALS(";;do{}loop;", getcode("char *s; do { } while (a);", "s"));
ASSERT_EQUALS(";;while1{}", getcode("char *s; while(true) { }", "s"));
ASSERT_EQUALS(";;while1{}", getcode("char *s; for(;;) { }", "s"));
ASSERT_EQUALS(";;while(var){}", getcode("char *s; while (s) { }", "s"));
ASSERT_EQUALS(";;while(!var){}", getcode("char *s; while (!s) { }", "s"));
ASSERT_EQUALS(";;alloc;while(var){}", getcode("int fd = open(a,b); while (fd >= 0) { }", "fd"));
ASSERT_EQUALS(";;alloc;while(!var){}", getcode("int fd = open(a,b); while (fd < 0) { }", "fd"));
// asprintf..
ASSERT_EQUALS(";;alloc;", getcode("char *s; asprintf(&s, \"xyz\");", "s"));
ASSERT_EQUALS(";;alloc;", getcode("char *s; asprintf(&s, \"s: %s\", s);", "s"));
ASSERT_EQUALS(";;;", getcode("char *s; asprintf(&p, \"s: %s\", s);", "s"));
// Since we don't check how the return value is used we must bail out
ASSERT_EQUALS("", getcode("char *s; int ret = asprintf(&s, \"xyz\");", "s"));
TODO_ASSERT_EQUALS(";;alloc;",
"", getcode("char *s; int ret; ret=asprintf(&s, \"xyz\"); if (ret==-1) return;", "s"));
// use..
ASSERT_EQUALS(";;use;", getcode("char *s; a(s);", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; (*a)(s);", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; abc.a(s);", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; s2 = s;", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; s2 = s + 10;", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; s2 = x + s;", "s"));
ASSERT_EQUALS(";;use;if{;}", getcode("char *s; if (foo(s)) ;", "s"));
ASSERT_EQUALS(";;use;", getcode("char *s; map1[s] = 0;", "s"));
ASSERT_EQUALS(";;;use;", getcode("char *p; const char *q; q = p;", "p"));
ASSERT_EQUALS(";;use;;", getcode("char *s; x = {1,s};", "s"));
ASSERT_EQUALS(";{};;alloc;;use;", getcode("struct Foo { }; Foo *p; p = malloc(10); const Foo *q; q = p;", "p"));
ASSERT_EQUALS(";;useuse_;", getcode("struct AB *ab; f(ab->a);", "ab"));
ASSERT_EQUALS(";;use;", getcode("struct AB *ab; ab = pop(ab);", "ab"));
// non-use..
ASSERT_EQUALS(";;use_;", getcode("char *s; c = x + s[0];","s"));
ASSERT_EQUALS(";;use_;", getcode("char *s; c = s[0] + x;","s"));
ASSERT_EQUALS(";;use_;", getcode("type *c; y = x + c->y;","c"));
ASSERT_EQUALS(";;use_;", getcode("type *c; y = c->y + x;","c"));
ASSERT_EQUALS(";;use_;", getcode("char *s; s = s + 1;", "s"));
ASSERT_EQUALS(";;dealloc;;", getcode("struct foo *s; free(s); printf(a,sizeof(*s));", "s"));
ASSERT_EQUALS(";;do{dealloc;;}while(var);", getcode("struct foo *s; do{free(s); printf(a,sizeof(*s));}while(s);", "s"));
// use reference
ASSERT_EQUALS(";;callfunc&use;", getcode("struct AB *ab; f(&ab);", "ab"));
// return..
ASSERT_EQUALS(";;return;", getcode("char *s; return;", "s"));
ASSERT_EQUALS(";;returnuse;", getcode("char *s; return s;", "s"));
ASSERT_EQUALS(";;return;", getcode("char *s; return 5 + s[0];", "s"));
// assign..
ASSERT_EQUALS(";;assign;", getcode("char *s; s = 0;", "s"));
ASSERT_EQUALS(";;;", getcode("char *s; s = strcpy(s, p);", "s"));
// callfunc..
ASSERT_EQUALS(";;assign;", getcode("char *s; s = a();", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; a();", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; abc.a();", "s"));
ASSERT_EQUALS(";;;", getcode("char *s; x = a();", "s")); // the function call is irrelevant
// exit..
ASSERT_EQUALS(";;exit;", getcode("char *s; exit(0);", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; _exit(0);", "s")); // not in std.cfg
ASSERT_EQUALS(";;exit;", getcode("char *s; abort();", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; err(0);", "s")); // not in std.cfg
ASSERT_EQUALS(";;if{exit;}", getcode("char *s; if (a) { exit(0); }", "s"));
ASSERT_EQUALS(";;if{exit;}", getcode("char *s; if (a) { ::exit(0); }", "s"));
ASSERT_EQUALS(";;if{exit;}", getcode("char *s; if (a) { std::exit(0); }", "s"));
// list_for_each
ASSERT_EQUALS(";;exit;{}}", getcode("void f() { char *s; list_for_each(x,y,s) { } }", "s"));
// open/close
ASSERT_EQUALS(";;alloc;if(var){dealloc;}", getcode("int f; f=open(a,b); if(f>=0)close(f);", "f"));
ASSERT_EQUALS(";;alloc;if(var){dealloc;}", getcode("int f; f=open(a,b); if(f>-1)close(f);", "f"));
ASSERT_EQUALS(";;alloc;ifv{;}", getcode("int f; f=open(a,b); if(f!=-1 || x);", "f"));
ASSERT_EQUALS(";;;dealloc;loop{}", getcode(";int f; while (close(f) == -1) { }", "f"));
ASSERT_EQUALS(";;;dealloc;assign;;", getcode(";int res; res = close(res);", "res"));
ASSERT_EQUALS(";;dealloc;", getcode("int f; e |= fclose(f);", "f"));
ASSERT_EQUALS(";;dealloc;", getcode("int f; e += fclose(f);", "f"));
ASSERT_EQUALS(";;dealloc;", getcode("int f; foo(fclose(f));", "f"));
// fcloseall..
ASSERT_EQUALS(";;alloc;;", getcode("char *s; s = malloc(10); fcloseall();", "s"));
ASSERT_EQUALS(";;alloc;dealloc;", getcode("FILE *f; f = fopen(a,b); fcloseall();", "f"));
// call memcpy in class function..
ASSERT_EQUALS(";;alloc;;", getcode("char *s; s = new char[10]; memcpy(s,a);", "s", true));
// #2112 - Segmentation fault in the getcode function
ASSERT_THROW(getcode("page *one = foo();\n"
"ASSERT(one, return 0)\n"
"const int two = rand();\n"
"return 0;\n"
"}", "one"), InternalError);
// ticket #2336: calling member function with same name as a white_list function
ASSERT_EQUALS(";;use;", getcode("char *s; foo.write(s);", "s"));
// #2473 - inner struct
ASSERT_EQUALS(";;alloc;{;;};dealloc;",
getcode("char *s = new char[10];\n"
"struct ab { int a, b; };\n"
"delete [] s;\n", "s"));
// #4405 - catch
ASSERT_EQUALS(";;catch{}", getcode("char *s; catch(err) { }", "s"));
}
bool test_white_list(const std::string& str, bool cpp = true) const {
return CheckMemoryLeakInFunction::test_white_list(str, &settings1, cpp);
}
void call_func() const {
// whitelist..
ASSERT_EQUALS(true, test_white_list("qsort"));
ASSERT_EQUALS(true, test_white_list("scanf"));
ASSERT_EQUALS(true, test_white_list("sscanf"));
// #1293
ASSERT_EQUALS(true, test_white_list("time"));
ASSERT_EQUALS(true, test_white_list("asctime"));
ASSERT_EQUALS(true, test_white_list("asctime_r"));
ASSERT_EQUALS(true, test_white_list("ctime"));
ASSERT_EQUALS(true, test_white_list("ctime_r"));
ASSERT_EQUALS(true, test_white_list("gmtime"));
ASSERT_EQUALS(true, test_white_list("gmtime_r"));
ASSERT_EQUALS(true, test_white_list("localtime"));
ASSERT_EQUALS(true, test_white_list("localtime_r"));
ASSERT_EQUALS(true, test_white_list("memcmp"));
ASSERT_EQUALS(true, test_white_list("gets"));
ASSERT_EQUALS(true, test_white_list("vprintf"));
ASSERT_EQUALS(true, test_white_list("vfprintf"));
ASSERT_EQUALS(true, test_white_list("vsprintf"));
ASSERT_EQUALS(true, test_white_list("snprintf"));
ASSERT_EQUALS(true, test_white_list("vsnprintf"));
ASSERT_EQUALS(true, test_white_list("delete", true));
ASSERT_EQUALS(false, test_white_list("delete", false));
static const char * const call_func_white_list[] = {
"access", "asprintf", "atof", "atoi", "atol", "chdir", "chmod", "clearerr", "chown"
, "fchmod", "fcntl", "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
, "flock", "for", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek"
, "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello", "ftruncate"
, "fwrite", "getc", "if", "ioctl", "lockf", "lseek", "open", "memchr", "memcpy"
, "memmove", "memset", "mkstemp", "perror", "posix_fadvise", "posix_fallocate", "pread"
, "printf", "puts", "pwrite", "read", "readahead", "readdir", "readdir_r", "readv"
, "realloc", "return", "rewind", "rewinddir", "scandir", "seekdir"
, "setbuf", "setbuffer", "setlinebuf", "setvbuf", "snprintf", "sprintf", "stpcpy", "strcasecmp"
, "strcat", "strchr", "strcmp", "strcpy", "stricmp", "strlen", "strncat", "strncmp"
, "strncpy", "strrchr", "strspn","strstr", "strtod", "strtol", "strtoul", "switch"
, "sync_file_range", "telldir", "typeid", "while", "write", "writev", "lstat", "stat"
, "_open", "_wopen", "vscanf", "vsscanf", "vfscanf", "vasprintf", "utime", "utimes", "unlink"
, "tempnam", "system", "symlink", "strpbrk", "strncasecmp", "strdup", "strcspn", "strcoll"
, "setlocale", "sethostname", "rmdir", "rindex", "rename", "remove", "adjtime", "creat", "execle"
, "execl", "execlp", "execve", "execv", "fmemopen", "fnmatch", "fopencookie", "fopen"
, "getgrnam", "gethostbyaddr", "getnetbyname", "getopt", "getopt_long", "getprotobyname", "getpwnam"
, "getservbyname", "getservbyport", "glob", "index", "inet_addr", "inet_aton", "inet_network"
, "initgroups", "link", "mblen", "mbstowcs", "mbtowc", "mkdir", "mkfifo", "mknod", "obstack_printf"
, "obstack_vprintf", "opendir", "parse_printf_format", "pathconf", "popen", "psignal"
, "readlink", "regcomp", "strxfrm", "wordexp", "sizeof", "strtok"
};
for (unsigned int i = 0; i < (sizeof(call_func_white_list) / sizeof(char *)); ++i) {
bool ret = test_white_list(call_func_white_list[i]);
ASSERT_EQUALS("", ret ? "" : call_func_white_list[i]);
}
}
std::string simplifycode(const char code[]) {
// Clear the error buffer..
errout.str("");
// Tokenize..
std::istringstream istr(code);
Tokenizer tokenizer(&settings0, this);
tokenizer.list.createTokens(istr, "test.cpp");
// replace "if ( ! var )" => "if(!var)"
for (Token *tok = tokenizer.list.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "if|while ( var )")) {
Token::eraseTokens(tok, tok->tokAt(4));
tok->str(tok->str() + "(var)");
}
else if (Token::Match(tok, "if|while ( ! var )")) {
Token::eraseTokens(tok, tok->tokAt(5));
tok->str(tok->str() + "(!var)");
}
}
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings0, this);
checkMemoryLeak.simplifycode(tokenizer.list.front());
return tokenizer.tokens()->stringifyList(0, false);
}
// Test that the CheckMemoryLeaksInFunction::simplifycode works
void simplifycode() {
ASSERT_EQUALS(";", simplifycode("; ; ; ;"));
ASSERT_EQUALS(";", simplifycode("; if ;"));
ASSERT_EQUALS("alloc ;", simplifycode("alloc ; if ; if(var) ; ifv ; if(!var) ;"));
ASSERT_EQUALS("alloc ;", simplifycode("alloc ; if ; else ;"));
// use..
ASSERT_EQUALS("; use ; }", simplifycode("; use use ; }"));
ASSERT_EQUALS("; use ; }", simplifycode("; use use_ ; }"));
ASSERT_EQUALS("; use ; }", simplifycode("; use_ use ; }"));
ASSERT_EQUALS("; use ; }", simplifycode("; &use use ; }"));
ASSERT_EQUALS("; use ; }", simplifycode("; use &use ; }"));
ASSERT_EQUALS("; alloc ; dealloc ; }", simplifycode("; alloc ; use ; use ; if use ; dealloc ; }"));
// if, else..
ASSERT_EQUALS("; alloc ; if break ; dealloc ;", simplifycode("; alloc ; if { break; } dealloc ;"));
ASSERT_EQUALS("; alloc ; if continue ; dealloc ;", simplifycode("; alloc ; if { continue; } dealloc ;"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc; if { return use; }"));
ASSERT_EQUALS("; alloc ; dealloc ;", simplifycode("; alloc; if(!var) { return; } dealloc;"));
ASSERT_EQUALS("; alloc ;", simplifycode("; if { alloc; } else { return; }"));
ASSERT_EQUALS("; alloc ; dealloc ;", simplifycode("; alloc ; if(!var) { alloc ; } dealloc ;"));
ASSERT_EQUALS("; use ;", simplifycode("; if(var) use ;"));
ASSERT_EQUALS("; break ;", simplifycode("; if break ; else break ;"));
ASSERT_EQUALS("; alloc ; if return ;", simplifycode("; alloc ; loop { if return ; if continue ; }"));
ASSERT_EQUALS("; alloc ; if return ;", simplifycode("; alloc ; loop { if continue ; else return ; }"));
ASSERT_EQUALS("; alloc ; if dealloc ;", simplifycode("; alloc ; if(!var) { return ; } if { dealloc ; }"));
ASSERT_EQUALS("; if alloc ; else assign ; return use ;", simplifycode("; callfunc ; if callfunc { alloc ; } else { assign ; } return use ;"));
ASSERT_EQUALS("; dealloc ; return ;", simplifycode("; while1 { if callfunc { dealloc ; return ; } else { continue ; } }"));
// remove outer if (#2733)
ASSERT_EQUALS("alloc ; return ; }", simplifycode("alloc ; if { if return use ; } return ; }"));
ASSERT_EQUALS("alloc ; return ; }", simplifycode("alloc ; if { if(var) return use ; } return ; }"));
ASSERT_EQUALS("alloc ; return ; }", simplifycode("alloc ; if(var) { if return use ; } return ; }"));
// "if ; .."
ASSERT_EQUALS("; if xxx ;", simplifycode("; if ; else xxx ;"));
ASSERT_EQUALS("; if(var) xxx ;", simplifycode("; if(!var) ; else xxx ;"));
ASSERT_EQUALS("; if(!var) xxx ;", simplifycode("; if(var) ; else xxx ;"));
ASSERT_EQUALS("; ifv xxx ;", simplifycode("; ifv ; else xxx ;"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc; if { dealloc; return; }"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc; if { return use; }"));
ASSERT_EQUALS("; alloc ; return ;", simplifycode(";alloc;if{return;}return;"));
ASSERT_EQUALS("; alloc ; if assign ; dealloc ;", simplifycode(";alloc;if{assign;}dealloc;"));
// if(var)
ASSERT_EQUALS("; alloc ; return use ;", simplifycode("; alloc ; return use ;"));
ASSERT_EQUALS("; alloc ; return use ;", simplifycode("; alloc ; ifv return ; return use ;"));
// switch..
ASSERT_EQUALS("; alloc ; dealloc ;", simplifycode(";alloc;switch{case;break;};dealloc;"));
ASSERT_EQUALS(";", simplifycode("; switch { case ; return ; default ; break ; }"));
ASSERT_EQUALS(";", simplifycode("; switch { case ; if { return ; } break ; default ; break ; }"));
ASSERT_EQUALS("; use ;", simplifycode("; switch { case ; return ; default ; use ; break ; }"));
ASSERT_EQUALS("; use ;", simplifycode("; while1 { loop { ; } switch { case ; dealloc ; return ; default ; break ; } }"));
ASSERT_EQUALS("; { dealloc ; return ; } }", simplifycode("switch { case ; case ; dealloc ; return ; default ; dealloc ; return ; } }"));
// loops..
ASSERT_EQUALS(";", simplifycode("; loop { ; }"));
ASSERT_EQUALS(";", simplifycode("; loop { break; }"));
ASSERT_EQUALS(";", simplifycode("; loop { if { break; } }"));
ASSERT_EQUALS("; loop alloc ;", simplifycode("; loop { alloc ; }"));
ASSERT_EQUALS("; alloc ; alloc ;", simplifycode("; alloc ; do { alloc ; } loop ;"));
ASSERT_EQUALS("; exit ;", simplifycode("; alloc ; do { } loop ; exit ;"));
ASSERT_EQUALS("; loop use ;", simplifycode("; loop { loop loop use ; } ;"));
ASSERT_EQUALS("; }", simplifycode("; loop { if break ; break ; } ; }"));
ASSERT_EQUALS("; }", simplifycode("; loop { if continue ; if continue ; } ; }"));
{
// ticket #3267
const char expected[] = "; loop if alloc ; if { dealloc ; return ; } }";
ASSERT_EQUALS(expected, simplifycode("; loop { if alloc ; } if { dealloc ; return ; } }"));
ASSERT_EQUALS(expected, simplifycode("; loop { if { alloc ; if(!var) { return ; } } } if { dealloc ; return ; } }"));
}
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc ; while(!var) alloc ;"));
ASSERT_EQUALS("; alloc ; dealloc ; return ;", simplifycode("; alloc ; while1 { if { dealloc ; return ; } }"));
ASSERT_EQUALS("; alloc ; dealloc ; return ;", simplifycode("; alloc ; while1 { if { dealloc ; return ; } if { continue ; } }"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc ; while1 { if { dealloc ; return ; } if { break ; } }"));
ASSERT_EQUALS("; alloc ; use ; }", simplifycode("; alloc ; while1 { if { dealloc ; return ; } continue ; } ; }"));
ASSERT_EQUALS(";", simplifycode("; do { dealloc ; alloc ; } while(var) ;"));
ASSERT_EQUALS("dealloc ; alloc ;", simplifycode("loop { dealloc ; alloc ; }"));
ASSERT_EQUALS("dealloc ; alloc ;", simplifycode("while1 { dealloc ; alloc ; }"));
ASSERT_EQUALS("use ; }", simplifycode("loop { use ; callfunc ; } }"));
ASSERT_EQUALS(";", simplifycode("; loop { if { continue ; } else { if continue ; } }"));
ASSERT_EQUALS(";", simplifycode("; loop { { if continue ; if continue ; } }"));
ASSERT_EQUALS("; use ;", simplifycode("; while1 { if { dealloc ; return ; } if { if { continue ; } } }"));
// scope..
TODO_ASSERT_EQUALS("; assign ; if alloc ; }",
"; assign ; dealloc ; if alloc ; }", simplifycode("; assign ; { dealloc ; if alloc ; } }"));
// callfunc..
ASSERT_EQUALS("; callfunc ; }", simplifycode(";callfunc;}"));
ASSERT_EQUALS(";", simplifycode(";callfunc;;"));
ASSERT_EQUALS("; callfunc ; }", simplifycode(";callfunc callfunc ; }"));
ASSERT_EQUALS("dealloc ; alloc ; return ; }", simplifycode("while1 { dealloc ; alloc ; } callfunc ; return ; }"));
ASSERT_EQUALS("; }", simplifycode("loop callfunc ; }"));
ASSERT_EQUALS("alloc ; dealloc ; }", simplifycode("alloc ; if { dealloc ; callfunc } dealloc ; }")); // #4405
// #2900 - don't report false positive
ASSERT_EQUALS("; alloc ; if { if { dealloc ; callfunc ; } return ; } dealloc ; }",
simplifycode("; alloc ; if { if { dealloc ; callfunc ; } return ; } dealloc ; }"));
// exit..
ASSERT_EQUALS("; exit ;", simplifycode("; alloc; exit;"));
ASSERT_EQUALS("; exit ;", simplifycode("; alloc; if { loop ; } dealloc; exit;"));
ASSERT_EQUALS(";", simplifycode("; if { alloc; exit; }"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc ; if { use; exit; }"));
ASSERT_EQUALS("; alloc ;", simplifycode("; alloc ; if(!var) { exit; }"));
TODO_ASSERT_EQUALS(";",
"; if(var) exit ;", simplifycode("; alloc ; if(var) { exit; }"));
TODO_ASSERT_EQUALS(";\n; alloc ;",
"; alloc ; ifv exit ;", simplifycode("; alloc ; ifv { exit; }"));
// try-catch
ASSERT_EQUALS("; }", simplifycode("; try ; catch exit ; }"));
// dealloc; dealloc;
ASSERT_EQUALS("; alloc ; if dealloc ; dealloc ;", simplifycode("; alloc ; if { dealloc ; } dealloc ;"));
// use ; dealloc ;
ASSERT_EQUALS("; alloc ; use ; if return ; dealloc ;", simplifycode("; alloc ; use ; if { return ; } dealloc ;"));
// #2635 - false negative
ASSERT_EQUALS("; alloc ; return use ; }",
simplifycode("; alloc ; if(!var) { loop { ifv { } } alloc ; } return use; }"));
}
// is there a leak in given code? if so, return the linenr
unsigned int dofindleak(const char code[]) {
// Clear the error buffer..
errout.str("");
settings0.debugwarnings = true;
// Tokenize..
std::istringstream istr(code);
TokenList list(&settings0);
list.createTokens(istr,"test.cpp");
Token *tokens=list.front();
// replace "if ( ! var )" => "if(!var)"
for (Token *tok = tokens; tok; tok = tok->next()) {
if (tok->str() == "if_var") {
tok->str("if(var)");
}
else if (Token::simpleMatch(tok, "if ( var )")) {
Token::eraseTokens(tok, tok->tokAt(4));
tok->str("if(var)");
}
else if (Token::simpleMatch(tok, "if ( ! var )")) {
Token::eraseTokens(tok, tok->tokAt(5));
tok->str("if(!var)");
}
}
const Token *tok = CheckMemoryLeakInFunction::findleak(tokens);
settings0.debugwarnings = false;
return (tok ? tok->linenr() : (unsigned int)(-1));
}
void findleak() {
static const unsigned int notfound = (unsigned int)(-1);
ASSERT_EQUALS(1, dofindleak("alloc;"));
ASSERT_EQUALS(1, dofindleak("; use; { alloc; }"));
ASSERT_EQUALS(2, dofindleak("alloc;\n return;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; return use;"));
ASSERT_EQUALS(2, dofindleak("alloc;\n callfunc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; use;"));
ASSERT_EQUALS(notfound, dofindleak("assign; alloc; dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("assign; if alloc; dealloc;"));
// if alloc..
ASSERT_EQUALS(2, dofindleak("if alloc;\n return;"));
ASSERT_EQUALS(notfound, dofindleak("if alloc;\n return use;"));
ASSERT_EQUALS(notfound, dofindleak("if alloc;\n use;"));
ASSERT_EQUALS(notfound, dofindleak("if alloc;\n if assign;\n if dealloc; }"));
// if..
ASSERT_EQUALS(notfound, dofindleak("alloc; ifv dealloc;"));
ASSERT_EQUALS(2, dofindleak("alloc;\n if return;\n dealloc;"));
ASSERT_EQUALS(2, dofindleak("alloc;\n if continue;\n dealloc;"));
ASSERT_EQUALS(2, dofindleak("alloc;\n if_var return;\n dealloc;"));
ASSERT_EQUALS(3, dofindleak("alloc;\n if\n return;\n dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; if { dealloc ; return; } dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; if { dealloc ; return; } dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; if { dealloc ; alloc; } dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc;\n if(!var)\n { callfunc;\n return;\n }\n use;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; if { return use; } dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc; if { dealloc; return; } dealloc;"));
ASSERT_EQUALS(5, dofindleak("{\n;\n alloc;\n if dealloc;\n}"));
// assign..
ASSERT_EQUALS(2, dofindleak("alloc;\n assign;\n dealloc;"));
ASSERT_EQUALS(notfound, dofindleak("alloc;\n if(!var) assign;\n dealloc;"));
ASSERT_EQUALS(2, dofindleak(";alloc;\n if assign;\n dealloc;"));
// loop..
TODO_ASSERT_EQUALS(1, notfound, dofindleak("; loop { alloc ; if break; dealloc ; }"));
TODO_ASSERT_EQUALS(1, notfound, dofindleak("; loop { alloc ; if continue; dealloc ; }"));
ASSERT_EQUALS(notfound, dofindleak("; loop { alloc ; if break; } dealloc ;"));
ASSERT_EQUALS(1, dofindleak("; loop alloc ;"));
ASSERT_EQUALS(1, dofindleak("; loop alloc ; dealloc ;"));
// callfunc (might be noreturn)
ASSERT_EQUALS(notfound, dofindleak("; alloc ; callfunc ; }"));
*/
}
@ -2912,11 +2355,6 @@ private:
ASSERT_EQUALS("", errout.str());
}
void realloc6() {
ASSERT_EQUALS(";;realloc;;", getcode("char *buf; buf=realloc(buf,100);", "buf"));
ASSERT_EQUALS(";;alloc;", getcode("char *buf; buf=realloc(0,100);", "buf"));
}
void realloc7() {
check("bool foo(size_t nLen, char* pData)\n"
"{\n"
@ -6079,7 +5517,6 @@ private:
CheckMemoryLeakInClass checkMemoryLeak2(&tokenizer, &settings, this);
CheckMemoryLeakStructMember checkMemoryLeak3(&tokenizer, &settings, this);
CheckMemoryLeakNoVar checkMemoryLeak4(&tokenizer, &settings, this);
checkMemoryLeak1.check();
checkMemoryLeak1.checkReallocUsage();
checkMemoryLeak2.check();
checkMemoryLeak3.check();
@ -6089,9 +5526,10 @@ private:
void run() override {
LOAD_LIB_2(settings.library, "gtk.cfg");
settings.addEnabled("all");
/*
TEST_CASE(glib1);
TEST_CASE(glib2); // #2806 - FP when using redundant assignment
*/
}
void glib1() {
@ -6198,15 +5636,15 @@ private:
// Check for memory leaks..
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this);
checkMemoryLeak.checkReallocUsage();
checkMemoryLeak.check();
}
void run() override {
LOAD_LIB_2(settings.library, "windows.cfg");
/*
TEST_CASE(openfileNoLeak);
TEST_CASE(returnValueNotUsed_tfopen_s);
TEST_CASE(sendMessage);
*/
}
void openfileNoLeak() {