📄 checkmemoryleak.cpp
字号:
tok2->str("use"); else if (tok2->str() == "dealloc_") tok2->str("dealloc"); else if (tok2->str() == "realloc") { tok2->str("dealloc"); tok2->insertToken("alloc"); tok2->insertToken(";"); } } simplifycode(tok, all); //tok->printOut("simplifycode result"); // If the variable is not allocated at all => no memory leak if (Token::findmatch(tok, "alloc") == 0) { Tokenizer::deleteTokens(tok); return; } // TODO : handle "goto" if (Token::findmatch(tok, "goto")) { Tokenizer::deleteTokens(tok); return; } if ((result = Token::findmatch(tok, "loop alloc ;")) != NULL) { MemoryLeak(result, varname, alloctype, all); } else if ((result = Token::findmatch(tok, "alloc ; if break|continue|return ;")) != NULL && Token::findmatch(tok, "dealloc ; alloc ; if continue ;") == NULL) { MemoryLeak(result->tokAt(3), varname, alloctype, all); } else if (_settings._showAll && (result = Token::findmatch(tok, "alloc ; ifv break|continue|return ;")) != NULL) { MemoryLeak(result->tokAt(3), varname, alloctype, all); } else if ((result = Token::findmatch(tok, "alloc ; alloc|assign|return ;")) != NULL) { MemoryLeak(result->tokAt(2), varname, alloctype, all); } else if ((result = Token::findmatch(tok, "dealloc ; dealloc ;")) != NULL) { _errorLogger->deallocDealloc(_tokenizer, result->tokAt(2), varname); } else if (! Token::findmatch(tok, "dealloc") && ! Token::findmatch(tok, "use") && ! Token::findmatch(tok, "return use ;")) { const Token *last = tok; while (last->next()) last = last->next(); MemoryLeak(last, varname, alloctype, all); } // detect cases that "simplifycode" don't handle well.. else if (_settings._debug) { Token *first = tok; while (first && first->str() == ";") first = first->next(); bool noerr = false; noerr |= Token::Match(first, "alloc ; }"); noerr |= Token::Match(first, "alloc ; dealloc ; }"); noerr |= Token::Match(first, "alloc ; return use ; }"); noerr |= Token::Match(first, "alloc ; use ; }"); noerr |= Token::Match(first, "alloc ; use ; return ; }"); noerr |= Token::Match(first, "if alloc ; dealloc ; }"); noerr |= Token::Match(first, "if alloc ; return use ; }"); noerr |= Token::Match(first, "if alloc ; use ; }"); noerr |= Token::Match(first, "alloc ; ifv return ; dealloc ; }"); noerr |= Token::Match(first, "alloc ; if return ; dealloc; }"); // Unhandled case.. if (! noerr) { std::cout << "Token listing..\n "; for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) std::cout << " " << tok2->str(); std::cout << "\n"; } } Tokenizer::deleteTokens(tok);}//---------------------------------------------------------------------------//---------------------------------------------------------------------------// Checks for memory leaks inside function..//---------------------------------------------------------------------------void CheckMemoryLeakClass::CheckMemoryLeak_InFunction(){ bool classmember = false; bool infunc = false; int indentlevel = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") --indentlevel; if (tok->str() == "::") classmember = true; // In function.. if (indentlevel == 0) { if (Token::Match(tok, ") {")) infunc = true; else if (Token::Match(tok, "[;}]")) infunc = classmember = false; } // Declare a local variable => Check if (indentlevel > 0 && infunc) { unsigned int sz = _tokenizer->SizeOfType(tok->strAt(1)); if (sz < 1) sz = 1; if (Token::Match(tok, "[{};] %type% * %var% [;=]")) CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(3), classmember, sz); else if (Token::Match(tok, "[{};] %type% %type% * %var% [;=]")) CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(4), classmember, sz); } }}//---------------------------------------------------------------------------//---------------------------------------------------------------------------// Checks for memory leaks in classes..//---------------------------------------------------------------------------void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers(){ int indentlevel = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") --indentlevel; else if (indentlevel == 0 && Token::Match(tok, "class %var% [{:]")) { std::vector<const char *> classname; classname.push_back(tok->strAt(1)); CheckMemoryLeak_ClassMembers_ParseClass(tok, classname); } }}void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector<const char *> &classname){ // Go into class. while (tok1 && tok1->str() != "{") tok1 = tok1->next(); if (tok1) tok1 = tok1->next(); int indentlevel = 0; for (const Token *tok = tok1; tok; tok = tok->next()) { if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") { --indentlevel; if (indentlevel < 0) return; } // Only parse this particular class.. not subclasses if (indentlevel > 0) continue; // Declaring subclass.. recursive checking if (Token::Match(tok, "class %var% [{:]")) { classname.push_back(tok->strAt(1)); CheckMemoryLeak_ClassMembers_ParseClass(tok, classname); classname.pop_back(); } // Declaring member variable.. check allocations and deallocations if (Token::Match(tok->next(), "%type% * %var% ;")) { // No false positives for auto deallocated classes.. if (_settings.isAutoDealloc(tok->strAt(1))) continue; if (tok->isName() || Token::Match(tok, "[;}]")) { if (_settings._showAll || !isclass(tok->tokAt(1))) CheckMemoryLeak_ClassMembers_Variable(classname, tok->tokAt(3)); } } }}void CheckMemoryLeakClass::CheckMemoryLeak_ClassMembers_Variable(const std::vector<const char *> &classname, const Token *tokVarname){ const char *varname = tokVarname->strAt(0); // Function pattern.. Check if member function std::ostringstream fpattern; for (unsigned int i = 0; i < classname.size(); i++) { fpattern << classname[i] << " :: "; } fpattern << "%var% ("; // Destructor pattern.. Check if class destructor.. std::ostringstream destructor; for (unsigned int i = 0; i < classname.size(); i++) { destructor << classname[i] << " :: "; } destructor << "~ " << classname.back() << " ("; // Pattern used in member function. "Var = ..." std::ostringstream varname_eq; varname_eq << varname << " ="; // Full variable name.. std::ostringstream FullVariableName; for (unsigned int i = 0; i < classname.size(); i++) FullVariableName << classname[i] << "::"; FullVariableName << varname; // Check if member variable has been allocated and deallocated.. AllocType Alloc = No; AllocType Dealloc = No; // Loop through all tokens. Inspect member functions bool memberfunction = false; int indentlevel = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (tok->str() == "{") ++indentlevel; else if (tok->str() == "}") --indentlevel; // Set the 'memberfunction' variable.. if (indentlevel == 0) { if (Token::Match(tok, "[;}]")) memberfunction = false; else if (Token::Match(tok, fpattern.str().c_str()) || Token::Match(tok, destructor.str().c_str())) memberfunction = true; } // Parse member function.. if (indentlevel > 0 && memberfunction) { // Allocate.. if (Token::Match(tok, varname_eq.str().c_str())) { AllocType alloc = GetAllocationType(tok->tokAt(2)); if (alloc != No) { if (Alloc != No && Alloc != alloc) alloc = Many; std::list<const Token *> callstack; if (alloc != Many && Dealloc != No && Dealloc != Many && Dealloc != alloc) { callstack.push_back(tok); _errorLogger->mismatchAllocDealloc(_tokenizer, callstack, FullVariableName.str()); callstack.pop_back(); } Alloc = alloc; } } // Deallocate.. const char *varnames[3] = { "var", 0, 0 }; varnames[0] = varname; AllocType dealloc = GetDeallocationType(tok, varnames); if (dealloc == No) { varnames[0] = "this"; varnames[1] = varname; dealloc = GetDeallocationType(tok, varnames); } if (dealloc != No) { if (Dealloc != No && Dealloc != dealloc) dealloc = Many; std::list<const Token *> callstack; if (dealloc != Many && Alloc != No && Alloc != Many && Alloc != dealloc) { callstack.push_back(tok); _errorLogger->mismatchAllocDealloc(_tokenizer, callstack, FullVariableName.str()); callstack.pop_back(); } Dealloc = dealloc; } } } if (Alloc != No && Dealloc == No) { MemoryLeak(tokVarname, FullVariableName.str().c_str(), Alloc, true); }}//---------------------------------------------------------------------------// Checks for memory leaks..//---------------------------------------------------------------------------void CheckMemoryLeakClass::CheckMemoryLeak(){ _listAllocFunc.clear(); // Check for memory leaks inside functions.. CheckMemoryLeak_InFunction(); // Check that all class members are deallocated.. if (_settings._showAll) CheckMemoryLeak_ClassMembers();}//---------------------------------------------------------------------------//---------------------------------------------------------------------------// Non-recursive function analysis//---------------------------------------------------------------------------Token * CheckMemoryLeakClass::functionParameterCode(const Token *ftok, int parameter){ int param = 1; // First parameter has index 1 // Extract the code for specified parameter... for (; ftok; ftok = ftok->next()) { if (ftok->str() == ")") break; if (ftok->str() == ",") { ++param; if (param > parameter) break; } if (param != parameter) continue; if (! Token::Match(ftok, "* %var% [,)]")) continue; // Extract and return the code for this parameter.. const char *parname = ftok->strAt(1); // Goto function implementation.. while (ftok && ftok->str() != "{") ftok = ftok->next(); ftok = ftok ? ftok->next() : NULL; // Return the code.. AllocType alloc = No, dealloc = No; bool all = false; std::list<const Token *> callstack; Token *code = getcode(ftok, callstack, parname, alloc, dealloc, false, all, 1); simplifycode(code, all); return code; } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -