MCPcopy Create free account
hub / github.com/cppcheck-opensource/cppcheck / checkInvalidFree

Method checkInvalidFree

lib/checkother.cpp:2740–2812  ·  view source on GitHub ↗

----------------------------------------------------------------------------- Check for a free() of an invalid address char* p = malloc(100); free(p + 10); -----------------------------------------------------------------------------

Source from the content-addressed store, hash-verified

2738// free(p + 10);
2739//-----------------------------------------------------------------------------
2740void CheckOtherImpl::checkInvalidFree()
2741{
2742 std::map<int, bool> inconclusive;
2743 std::map<int, std::string> allocation;
2744
2745 logChecker("CheckOther::checkInvalidFree");
2746
2747 const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive);
2748 const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
2749 for (const Scope * scope : symbolDatabase->functionScopes) {
2750 for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
2751
2752 // Keep track of which variables were assigned addresses to newly-allocated memory
2753 if ((tok->isCpp() && Token::Match(tok, "%var% = new")) ||
2754 (Token::Match(tok, "%var% = %name% (") && mSettings.library.getAllocFuncInfo(tok->tokAt(2)))) {
2755 allocation.emplace(tok->varId(), tok->strAt(2));
2756 inconclusive.emplace(tok->varId(), false);
2757 }
2758
2759 // If a previously-allocated pointer is incremented or decremented, any subsequent
2760 // free involving pointer arithmetic may or may not be invalid, so we should only
2761 // report an inconclusive result.
2762 else if (Token::Match(tok, "%var% = %name% +|-") &&
2763 tok->varId() == tok->tokAt(2)->varId() &&
2764 allocation.find(tok->varId()) != allocation.end()) {
2765 if (printInconclusive)
2766 inconclusive[tok->varId()] = true;
2767 else {
2768 allocation.erase(tok->varId());
2769 inconclusive.erase(tok->varId());
2770 }
2771 }
2772
2773 // If a previously-allocated pointer is assigned a completely new value,
2774 // we can't know if any subsequent free() on that pointer is valid or not.
2775 else if (Token::Match(tok, "%var% =")) {
2776 allocation.erase(tok->varId());
2777 inconclusive.erase(tok->varId());
2778 }
2779
2780 // If a variable that was previously assigned a newly-allocated memory location is
2781 // added or subtracted from when used to free the memory, report an error.
2782 else if ((Token::Match(tok, "%name% ( %any% +|-") && mSettings.library.getDeallocFuncInfo(tok)) ||
2783 Token::Match(tok, "delete [ ] ( %any% +|-") ||
2784 Token::Match(tok, "delete %any% +|- %any%")) {
2785
2786 const int varIndex = tok->strAt(1) == "(" ? 2 :
2787 tok->strAt(3) == "(" ? 4 : 1;
2788 const int var1 = tok->tokAt(varIndex)->varId();
2789 const int var2 = tok->tokAt(varIndex + 2)->varId();
2790 const auto alloc1 = utils::as_const(inconclusive).find(var1);
2791 const auto alloc2 = utils::as_const(inconclusive).find(var2);
2792 if (alloc1 != inconclusive.end()) {
2793 invalidFreeError(tok, allocation[var1], alloc1->second);
2794 } else if (alloc2 != inconclusive.end()) {
2795 invalidFreeError(tok, allocation[var2], alloc2->second);
2796 }
2797 }

Callers 1

runChecksMethod · 0.45

Calls 11

nextMethod · 0.80
getAllocFuncInfoMethod · 0.80
getDeallocFuncInfoMethod · 0.80
isFunctionConstMethod · 0.80
linkAtMethod · 0.80
isEnabledMethod · 0.45
tokAtMethod · 0.45
findMethod · 0.45
endMethod · 0.45
eraseMethod · 0.45
strMethod · 0.45

Tested by

no test coverage detected