| 416 | //--------------------------------------------------------------------------- |
| 417 | |
| 418 | void CheckMemoryLeakInFunctionImpl::checkReallocUsage() |
| 419 | { |
| 420 | logChecker("CheckMemoryLeakInFunction::checkReallocUsage"); |
| 421 | |
| 422 | // only check functions |
| 423 | const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 424 | for (const Scope * scope : symbolDatabase->functionScopes) { |
| 425 | |
| 426 | // Search for the "var = realloc(var, 100" pattern within this function |
| 427 | for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { |
| 428 | if (tok->varId() > 0 && Token::Match(tok, "%name% =")) { |
| 429 | // Get the parenthesis in "realloc(" |
| 430 | const Token* parTok = tok->next()->astOperand2(); |
| 431 | // Skip casts |
| 432 | while (parTok && parTok->isCast()) |
| 433 | parTok = parTok->astOperand1(); |
| 434 | if (!parTok) |
| 435 | continue; |
| 436 | |
| 437 | const Token *const reallocTok = parTok->astOperand1(); |
| 438 | if (!reallocTok) |
| 439 | continue; |
| 440 | const Library::AllocFunc* f = mSettings.library.getReallocFuncInfo(reallocTok); |
| 441 | if (!(f && f->arg == -1 && mSettings.library.isnotnoreturn(reallocTok))) |
| 442 | continue; |
| 443 | |
| 444 | const AllocType allocType = getReallocationType(reallocTok, tok->varId()); |
| 445 | if (!(allocType == Malloc || allocType == OtherMem)) |
| 446 | continue; |
| 447 | const Token* arg = getArguments(reallocTok).at(f->reallocArg - 1); |
| 448 | while (arg && arg->isCast()) |
| 449 | arg = arg->astOperand1(); |
| 450 | const Token* tok2 = tok; |
| 451 | while (arg && arg->isUnaryOp("*") && tok2 && tok2->astParent() && tok2->astParent()->isUnaryOp("*")) { |
| 452 | arg = arg->astOperand1(); |
| 453 | tok2 = tok2->astParent(); |
| 454 | } |
| 455 | |
| 456 | if (!arg || !tok2) |
| 457 | continue; |
| 458 | |
| 459 | if (!(tok->varId() == arg->varId() && tok->variable() && !tok->variable()->isArgument())) |
| 460 | continue; |
| 461 | |
| 462 | // Check that another copy of the pointer wasn't saved earlier in the function |
| 463 | if (Token::findmatch(scope->bodyStart, "%name% = %varid% ;", tok, tok->varId()) || |
| 464 | Token::findmatch(scope->bodyStart, "[{};] %varid% = *| %var%", tok, tok->varId())) |
| 465 | continue; |
| 466 | if (const Token* storeTok = Token::findmatch(scope->bodyStart, "[{};] %varid% = %name% (", tok, tok->varId())) |
| 467 | if (storeTok->tokAt(3) != reallocTok && !mSettings.library.getAllocFuncInfo(storeTok->tokAt(3))) |
| 468 | continue; |
| 469 | |
| 470 | // Check if the argument is known to be null, which means it is not a memory leak |
| 471 | if (arg->hasKnownIntValue() && arg->getKnownIntValue() == 0) { |
| 472 | continue; |
| 473 | } |
| 474 | |
| 475 | const Token* tokEndRealloc = reallocTok->linkAt(1); |