Cppcheck
checkleakautovar.cpp
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 //---------------------------------------------------------------------------
00020 // Leaks when using auto variables
00021 //---------------------------------------------------------------------------
00022 
00023 #include "checkleakautovar.h"
00024 
00025 #include "checkmemoryleak.h"  // <- CheckMemoryLeak::memoryLeak
00026 #include "checkother.h"   // <- doubleFreeError
00027 
00028 #include "tokenize.h"
00029 #include "errorlogger.h"
00030 #include "symboldatabase.h"
00031 
00032 #include <fstream>
00033 
00034 //---------------------------------------------------------------------------
00035 
00036 // Register this check class (by creating a static instance of it)
00037 namespace {
00038     CheckLeakAutoVar instance;
00039 }
00040 
00041 //---------------------------------------------------------------------------
00042 
00043 void VarInfo::print()
00044 {
00045     std::cout << "size=" << alloctype.size() << std::endl;
00046     std::map<unsigned int, std::string>::const_iterator it;
00047     for (it = alloctype.begin(); it != alloctype.end(); ++it) {
00048         std::string strusage;
00049         std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(it->first);
00050         if (use != possibleUsage.end())
00051             strusage = use->second;
00052 
00053         std::cout << "alloctype='" << it->second << "' "
00054                   << "possibleUsage='" << strusage << "'" << std::endl;
00055     }
00056 }
00057 
00058 void VarInfo::possibleUsageAll(const std::string &functionName)
00059 {
00060     possibleUsage.clear();
00061     std::map<unsigned int, std::string>::const_iterator it;
00062     for (it = alloctype.begin(); it != alloctype.end(); ++it)
00063         possibleUsage[it->first] = functionName;
00064 }
00065 
00066 
00067 void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, const std::string &type)
00068 {
00069     const CheckMemoryLeak checkmemleak(_tokenizer, _errorLogger, _settings->standards);
00070     if (type == "fopen")
00071         checkmemleak.resourceLeakError(tok, varname);
00072     else
00073         checkmemleak.memleakError(tok, varname);
00074     //reportError(tok, Severity::error, "newleak", "New memory leak: " + varname);
00075 }
00076 
00077 void CheckLeakAutoVar::mismatchError(const Token *tok, const std::string &varname)
00078 {
00079     const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards);
00080     std::list<const Token *> callstack(1, tok);
00081     c.mismatchAllocDealloc(callstack, varname);
00082     //reportError(tok, Severity::error, "newmismatch", "New mismatching allocation and deallocation: " + varname);
00083 }
00084 
00085 void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname)
00086 {
00087     const CheckMemoryLeak c(_tokenizer, _errorLogger, _settings->standards);
00088     c.deallocuseError(tok, varname);
00089     //reportError(tok, Severity::error, "newdeallocuse", "Using deallocated pointer " + varname);
00090 }
00091 
00092 void CheckLeakAutoVar::deallocReturnError(const Token *tok, const std::string &varname)
00093 {
00094     reportError(tok, Severity::error, "deallocret", "Returning/dereferencing '" + varname + "' after it is deallocated / released");
00095 }
00096 
00097 void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::string &functionName)
00098 {
00099     if (((!cfgalloc.empty() || !cfgdealloc.empty()) && _settings->isEnabled("information")) || _settings->experimental) {
00100         reportError(tok,
00101                     Severity::information,
00102                     "leakconfiguration",
00103                     functionName + " configuration is needed to establish if there is a leak or not");
00104     }
00105 }
00106 
00107 void CheckLeakAutoVar::parseConfigurationFile(const std::string &filename)
00108 {
00109     std::ifstream fin(filename.c_str());
00110     if (!fin.is_open())
00111         return;
00112 
00113     std::string line;
00114     while (std::getline(fin,line)) {
00115         if (line.compare(0,4,"MEM ",0,4) == 0) {
00116             std::string f1;
00117             enum {ALLOC, DEALLOC} type = ALLOC;
00118             std::string::size_type pos1 = line.find_first_not_of(" ", 4U);
00119             while (pos1 < line.size()) {
00120                 const std::string::size_type pos2 = line.find(" ", pos1);
00121                 std::string f;
00122                 if (pos2 == std::string::npos)
00123                     f = line.substr(pos1);
00124                 else
00125                     f = line.substr(pos1, pos2-pos1);
00126                 if (f1.empty())
00127                     f1 = f;
00128                 if (f == ":")
00129                     type = DEALLOC;
00130                 else if (type == ALLOC)
00131                     cfgalloc[f] = f1;
00132                 else if (type == DEALLOC)
00133                     cfgdealloc[f] = f1;
00134                 pos1 = line.find_first_not_of(" ", pos2);
00135             }
00136         }
00137 
00138         else if (line.compare(0,7,"IGNORE ",0,7) == 0) {
00139             std::string::size_type pos1 = line.find_first_not_of(" ", 7U);
00140             while (pos1 < line.size()) {
00141                 std::string::size_type pos2 = line.find_first_of(" ", pos1);
00142                 std::string functionName;
00143                 if (pos2 == std::string::npos)
00144                     functionName = line.substr(pos1);
00145                 else
00146                     functionName = line.substr(pos1, pos2-pos1);
00147                 cfgignore.insert(functionName);
00148                 pos1 = line.find_first_not_of(" ", pos2);
00149             }
00150         }
00151 
00152         else if (line.compare(0,4,"USE ",0,4) == 0) {
00153             std::string::size_type pos1 = line.find_first_not_of(" ", 4U);
00154             while (pos1 < line.size()) {
00155                 std::string::size_type pos2 = line.find_first_of(" ", pos1);
00156                 std::string functionName;
00157                 if (pos2 == std::string::npos)
00158                     functionName = line.substr(pos1);
00159                 else
00160                     functionName = line.substr(pos1, pos2-pos1);
00161                 cfguse.insert(functionName);
00162                 pos1 = line.find_first_not_of(" ", pos2);
00163             }
00164         }
00165 
00166         else if (line.compare(0,9,"NORETURN ",0,9) == 0) {
00167             std::string::size_type pos1 = line.find_first_not_of(" ", 9U);
00168             while (pos1 < line.size()) {
00169                 std::string::size_type pos2 = line.find_first_of(" ", pos1);
00170                 std::string functionName;
00171                 if (pos2 == std::string::npos)
00172                     functionName = line.substr(pos1);
00173                 else
00174                     functionName = line.substr(pos1, pos2-pos1);
00175                 cfgnoreturn.insert(functionName);
00176                 pos1 = line.find_first_not_of(" ", pos2);
00177             }
00178         }
00179     }
00180 }
00181 
00182 void CheckLeakAutoVar::check()
00183 {
00184     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00185 
00186     // Check function scopes
00187     const std::size_t functions = symbolDatabase->functionScopes.size();
00188     for (std::size_t i = 0; i < functions; ++i) {
00189         const Scope * scope = symbolDatabase->functionScopes[i];
00190         // Empty variable info
00191         VarInfo varInfo;
00192 
00193         // Local variables that are known to be non-zero.
00194         static const std::set<unsigned int> notzero;
00195 
00196         checkScope(scope->classStart, &varInfo, notzero);
00197 
00198         varInfo.conditionalAlloc.clear();
00199 
00200         // Clear reference arguments from varInfo..
00201         std::map<unsigned int, std::string>::iterator it = varInfo.alloctype.begin();
00202         while (it != varInfo.alloctype.end()) {
00203             const Variable *var = symbolDatabase->getVariableFromVarId(it->first);
00204             if (!var ||
00205                 (var->isArgument() && var->isReference()) ||
00206                 (!var->isArgument() && !var->isLocal()))
00207                 varInfo.alloctype.erase(it++);
00208             else
00209                 ++it;
00210         }
00211 
00212         ret(scope->classEnd, varInfo);
00213     }
00214 }
00215 
00216 void CheckLeakAutoVar::checkScope(const Token * const startToken,
00217                                   VarInfo *varInfo,
00218                                   std::set<unsigned int> notzero)
00219 {
00220     std::map<unsigned int, std::string> &alloctype = varInfo->alloctype;
00221     std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage;
00222     const std::set<unsigned int> conditionalAlloc(varInfo->conditionalAlloc);
00223 
00224     // Allocation functions. key = function name, value = allocation type
00225     std::map<std::string, std::string> allocFunctions(cfgalloc);
00226     allocFunctions["malloc"] = "malloc";
00227     allocFunctions["strdup"] = "malloc";
00228     allocFunctions["fopen"] = "fopen";
00229 
00230     // Deallocation functions. key = function name, value = allocation type
00231     std::map<std::string, std::string> deallocFunctions(cfgdealloc);
00232     deallocFunctions["free"] = "malloc";
00233     deallocFunctions["fclose"] = "fopen";
00234 
00235     // Parse all tokens
00236     const Token * const endToken = startToken->link();
00237     for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next()) {
00238         // Deallocation and then dereferencing pointer..
00239         if (tok->varId() > 0) {
00240             const std::map<unsigned int, std::string>::iterator var = alloctype.find(tok->varId());
00241             if (var != alloctype.end()) {
00242                 if (var->second == "dealloc" && !Token::Match(tok->previous(), "[;{},=] %var% =")) {
00243                     deallocUseError(tok, tok->str());
00244                 } else if (Token::simpleMatch(tok->tokAt(-2), "= &")) {
00245                     varInfo->erase(tok->varId());
00246                 } else if (tok->strAt(-1) == "=") {
00247                     varInfo->erase(tok->varId());
00248                 }
00249             } else if (Token::Match(tok->previous(), "& %var% = %var% ;")) {
00250                 varInfo->referenced.insert(tok->tokAt(2)->varId());
00251             }
00252         }
00253 
00254         if (tok->str() == "(" && tok->previous()->isName()) {
00255             functionCall(tok->previous(), varInfo, "");
00256             tok = tok->link();
00257             continue;
00258         }
00259 
00260         // look for end of statement
00261         if (!Token::Match(tok, "[;{}]") || Token::Match(tok->next(), "[;{}]"))
00262             continue;
00263         tok = tok->next();
00264         if (!tok || tok == endToken)
00265             break;
00266 
00267         // parse statement
00268 
00269         // assignment..
00270         if (tok->varId() && Token::Match(tok, "%var% =")) {
00271             // taking address of another variable..
00272             if (Token::Match(tok->next(), "= %var% [+;]")) {
00273                 if (tok->tokAt(2)->varId() != tok->varId()) {
00274                     // If variable points at allocated memory => error
00275                     leakIfAllocated(tok, *varInfo);
00276 
00277                     // no multivariable checking currently => bail out for rhs variables
00278                     for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
00279                         if (tok2->str() == ";") {
00280                             break;
00281                         }
00282                         if (tok2->varId()) {
00283                             varInfo->erase(tok2->varId());
00284                         }
00285                     }
00286                 }
00287             }
00288 
00289             // is variable used in rhs?
00290             bool used_in_rhs = false;
00291             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
00292                 if (tok2->str() == ";") {
00293                     break;
00294                 }
00295                 if (tok->varId() == tok2->varId()) {
00296                     used_in_rhs = true;
00297                     break;
00298                 }
00299             }
00300             // TODO: Better checking how the pointer is used in rhs?
00301             if (used_in_rhs)
00302                 continue;
00303 
00304             // Variable has already been allocated => error
00305             if (conditionalAlloc.find(tok->varId()) == conditionalAlloc.end())
00306                 leakIfAllocated(tok, *varInfo);
00307             varInfo->erase(tok->varId());
00308 
00309             // not a local variable nor argument?
00310             const Variable *var = tok->variable();
00311             if (var && !var->isArgument() && !var->isLocal()) {
00312                 continue;
00313             }
00314 
00315             // Don't check reference variables
00316             if (var && var->isReference())
00317                 continue;
00318 
00319             // allocation?
00320             if (Token::Match(tok->tokAt(2), "%type% (")) {
00321                 const std::map<std::string, std::string>::const_iterator it = allocFunctions.find(tok->strAt(2));
00322                 if (it != allocFunctions.end()) {
00323                     alloctype[tok->varId()] = it->second;
00324                 }
00325             }
00326 
00327             // Assigning non-zero value variable. It might be used to
00328             // track the execution for a later if condition.
00329             if (Token::Match(tok->tokAt(2), "%num% ;") && MathLib::toLongNumber(tok->strAt(2)) != 0)
00330                 notzero.insert(tok->varId());
00331             else if (Token::Match(tok->tokAt(2), "- %type% ;") && tok->tokAt(3)->isUpperCaseName())
00332                 notzero.insert(tok->varId());
00333             else
00334                 notzero.erase(tok->varId());
00335         }
00336 
00337         // if/else
00338         else if (Token::simpleMatch(tok, "if (")) {
00339             // Parse function calls inside the condition
00340             for (const Token *innerTok = tok->tokAt(2); innerTok; innerTok = innerTok->next()) {
00341                 if (innerTok->str() == ")")
00342                     break;
00343                 if (innerTok->str() == "(" && innerTok->previous()->isName()) {
00344                     std::string dealloc;
00345                     {
00346                         const std::map<std::string, std::string>::iterator func = deallocFunctions.find(tok->str());
00347                         if (func != deallocFunctions.end()) {
00348                             dealloc = func->second;
00349                         }
00350                     }
00351 
00352                     functionCall(innerTok->previous(), varInfo, dealloc);
00353                     innerTok = innerTok->link();
00354                 }
00355             }
00356 
00357             const Token *tok2 = tok->linkAt(1);
00358             if (Token::simpleMatch(tok2, ") {")) {
00359                 VarInfo varInfo1(*varInfo);
00360                 VarInfo varInfo2(*varInfo);
00361 
00362                 if (Token::Match(tok->next(), "( %var% )")) {
00363                     varInfo2.erase(tok->tokAt(2)->varId());
00364                     if (notzero.find(tok->tokAt(2)->varId()) != notzero.end())
00365                         varInfo2.clear();
00366                 } else if (Token::Match(tok->next(), "( ! %var% )|&&")) {
00367                     varInfo1.erase(tok->tokAt(3)->varId());
00368                 } else if (Token::Match(tok->next(), "( %var% ( ! %var% ) )|&&")) {
00369                     varInfo1.erase(tok->tokAt(5)->varId());
00370                 }
00371 
00372                 checkScope(tok2->next(), &varInfo1, notzero);
00373                 tok2 = tok2->linkAt(1);
00374                 if (Token::simpleMatch(tok2, "} else {")) {
00375                     checkScope(tok2->tokAt(2), &varInfo2, notzero);
00376                     tok = tok2->linkAt(2)->previous();
00377                 } else {
00378                     tok = tok2->previous();
00379                 }
00380 
00381                 VarInfo old;
00382                 old.swap(*varInfo);
00383 
00384                 // Conditional allocation in varInfo1
00385                 std::map<unsigned int, std::string>::const_iterator it;
00386                 for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) {
00387                     if (varInfo2.alloctype.find(it->first) == varInfo2.alloctype.end() &&
00388                         old.alloctype.find(it->first) == old.alloctype.end()) {
00389                         varInfo->conditionalAlloc.insert(it->first);
00390                     }
00391                 }
00392 
00393                 // Conditional allocation in varInfo2
00394                 for (it = varInfo2.alloctype.begin(); it != varInfo2.alloctype.end(); ++it) {
00395                     if (varInfo1.alloctype.find(it->first) == varInfo1.alloctype.end() &&
00396                         old.alloctype.find(it->first) == old.alloctype.end()) {
00397                         varInfo->conditionalAlloc.insert(it->first);
00398                     }
00399                 }
00400 
00401                 // Conditional allocation/deallocation
00402                 for (it = varInfo1.alloctype.begin(); it != varInfo1.alloctype.end(); ++it) {
00403                     if (it->second == "dealloc" && conditionalAlloc.find(it->first) != conditionalAlloc.end()) {
00404                         varInfo->conditionalAlloc.erase(it->first);
00405                         varInfo2.erase(it->first);
00406                     }
00407                 }
00408                 for (it = varInfo2.alloctype.begin(); it != varInfo2.alloctype.end(); ++it) {
00409                     if (it->second == "dealloc" && conditionalAlloc.find(it->first) != conditionalAlloc.end()) {
00410                         varInfo->conditionalAlloc.erase(it->first);
00411                         varInfo1.erase(it->first);
00412                     }
00413                 }
00414 
00415                 alloctype.insert(varInfo1.alloctype.begin(), varInfo1.alloctype.end());
00416                 alloctype.insert(varInfo2.alloctype.begin(), varInfo2.alloctype.end());
00417 
00418                 possibleUsage.insert(varInfo1.possibleUsage.begin(), varInfo1.possibleUsage.end());
00419                 possibleUsage.insert(varInfo2.possibleUsage.begin(), varInfo2.possibleUsage.end());
00420             }
00421         }
00422 
00423         // unknown control..
00424         else if (Token::Match(tok, "%type% (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
00425             varInfo->clear();
00426             break;
00427         }
00428 
00429         // Function call..
00430         else if (Token::Match(tok, "%type% (") && tok->str() != "return") {
00431             std::string dealloc;
00432             {
00433                 const std::map<std::string, std::string>::iterator func = deallocFunctions.find(tok->str());
00434                 if (func != deallocFunctions.end()) {
00435                     dealloc = func->second;
00436                 }
00437             }
00438 
00439             functionCall(tok, varInfo, dealloc);
00440 
00441             tok = tok->next()->link();
00442 
00443             // Handle scopes that might be noreturn
00444             if (dealloc.empty() && Token::simpleMatch(tok, ") ; }")) {
00445                 const std::string &functionName(tok->link()->previous()->str());
00446                 bool unknown = false;
00447                 if (cfgignore.find(functionName) == cfgignore.end() &&
00448                     cfguse.find(functionName) == cfguse.end() &&
00449                     _tokenizer->IsScopeNoReturn(tok->tokAt(2), &unknown)) {
00450                     if (unknown) {
00451                         //const std::string &functionName(tok->link()->previous()->str());
00452                         varInfo->possibleUsageAll(functionName);
00453                     } else {
00454                         varInfo->clear();
00455                     }
00456                 }
00457             }
00458 
00459             continue;
00460         }
00461 
00462         // return
00463         else if (tok->str() == "return") {
00464             ret(tok, *varInfo);
00465             varInfo->clear();
00466         }
00467 
00468         // goto => weird execution path
00469         else if (tok->str() == "goto") {
00470             varInfo->clear();
00471         }
00472 
00473         // throw
00474         // TODO: if the execution leave the function then treat it as return
00475         else if (tok->str() == "throw") {
00476             varInfo->clear();
00477         }
00478     }
00479 }
00480 
00481 void CheckLeakAutoVar::functionCall(const Token *tok, VarInfo *varInfo, const std::string &dealloc)
00482 {
00483     std::map<unsigned int, std::string> &alloctype = varInfo->alloctype;
00484     std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage;
00485 
00486     // Ignore function call?
00487     const bool ignore = bool(cfgignore.find(tok->str()) != cfgignore.end());
00488     //const bool use = bool(cfguse.find(tok->str()) != cfguse.end());
00489 
00490     if (ignore)
00491         return;
00492 
00493     for (const Token *arg = tok->tokAt(2); arg; arg = arg->nextArgument()) {
00494         if ((Token::Match(arg, "%var% [-,)]") && arg->varId() > 0) ||
00495             (Token::Match(arg, "& %var%") && arg->next()->varId() > 0)) {
00496 
00497             // goto variable
00498             if (arg->str() == "&")
00499                 arg = arg->next();
00500 
00501             // Is variable allocated?
00502             const std::map<unsigned int,std::string>::iterator var = alloctype.find(arg->varId());
00503             if (var != alloctype.end()) {
00504                 if (dealloc.empty()) {
00505                     // possible usage
00506                     possibleUsage[arg->varId()] = tok->str();
00507                     if (var->second == "dealloc" && arg->previous()->str() == "&")
00508                         varInfo->erase(arg->varId());
00509                 } else if (var->second == "dealloc") {
00510                     CheckOther checkOther(_tokenizer, _settings, _errorLogger);
00511                     checkOther.doubleFreeError(tok, arg->str());
00512                 } else if (var->second != dealloc) {
00513                     // mismatching allocation and deallocation
00514                     mismatchError(tok, arg->str());
00515                     varInfo->erase(arg->varId());
00516                 } else {
00517                     // deallocation
00518                     var->second = "dealloc";
00519                 }
00520             } else if (!dealloc.empty()) {
00521                 alloctype[arg->varId()] = "dealloc";
00522             }
00523         } else if (Token::Match(arg, "%var% (")) {
00524             functionCall(arg, varInfo, dealloc);
00525         }
00526     }
00527 }
00528 
00529 
00530 void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
00531                                        const VarInfo &varInfo)
00532 {
00533     const std::map<unsigned int, std::string> &alloctype = varInfo.alloctype;
00534     const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage;
00535 
00536     const std::map<unsigned int,std::string>::const_iterator var = alloctype.find(vartok->varId());
00537     if (var != alloctype.end() && var->second != "dealloc") {
00538         const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(vartok->varId());
00539         if (use == possibleUsage.end()) {
00540             leakError(vartok, vartok->str(), var->second);
00541         } else {
00542             configurationInfo(vartok, use->second);
00543         }
00544     }
00545 }
00546 
00547 void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
00548 {
00549     const std::map<unsigned int, std::string> &alloctype = varInfo.alloctype;
00550     const std::map<unsigned int, std::string> &possibleUsage = varInfo.possibleUsage;
00551 
00552     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
00553     for (std::map<unsigned int, std::string>::const_iterator it = alloctype.begin(); it != alloctype.end(); ++it) {
00554         // don't warn if variable is conditionally allocated
00555         if (it->second != "dealloc" && varInfo.conditionalAlloc.find(it->first) != varInfo.conditionalAlloc.end())
00556             continue;
00557 
00558         // don't warn if there is a reference of the variable
00559         if (varInfo.referenced.find(it->first) != varInfo.referenced.end())
00560             continue;
00561 
00562         const unsigned int varid = it->first;
00563         const Variable *var = symbolDatabase->getVariableFromVarId(varid);
00564         if (var) {
00565             bool used = false;
00566             for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
00567                 if (tok2->str() == ";")
00568                     break;
00569                 if (Token::Match(tok2, "return|(|, %varid% [);,]", varid)) {
00570                     used = true;
00571                     break;
00572                 }
00573                 if (Token::Match(tok2, "return|(|, & %varid% . %var% [);,]", varid)) {
00574                     used = true;
00575                     break;
00576                 }
00577             }
00578 
00579             // return deallocated pointer
00580             if (used && it->second == "dealloc")
00581                 deallocReturnError(tok, var->name());
00582 
00583             else if (!used && it->second != "dealloc") {
00584 
00585                 const std::map<unsigned int, std::string>::const_iterator use = possibleUsage.find(varid);
00586                 if (use == possibleUsage.end()) {
00587                     leakError(tok, var->name(), it->second);
00588                 } else {
00589                     configurationInfo(tok, use->second);
00590                 }
00591             }
00592         }
00593     }
00594 }