| 89 | |
| 90 | |
| 91 | void CheckExceptionSafetyImpl::deallocThrow() |
| 92 | { |
| 93 | if (!mSettings.severity.isEnabled(Severity::warning) && !mSettings.isPremiumEnabled("exceptDeallocThrow")) |
| 94 | return; |
| 95 | |
| 96 | logChecker("CheckExceptionSafety::deallocThrow"); // warning |
| 97 | |
| 98 | const bool printInconclusive = mSettings.certainty.isEnabled(Certainty::inconclusive); |
| 99 | const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 100 | |
| 101 | // Deallocate a global/member pointer and then throw exception |
| 102 | // the pointer will be a dead pointer |
| 103 | for (const Scope * scope : symbolDatabase->functionScopes) { |
| 104 | for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { |
| 105 | // only looking for delete now |
| 106 | if (tok->str() != "delete") |
| 107 | continue; |
| 108 | |
| 109 | // Check if this is something similar with: "delete p;" |
| 110 | tok = tok->next(); |
| 111 | if (Token::simpleMatch(tok, "[ ]")) |
| 112 | tok = tok->tokAt(2); |
| 113 | if (!tok || tok == scope->bodyEnd) |
| 114 | break; |
| 115 | if (!Token::Match(tok, "%var% ;")) |
| 116 | continue; |
| 117 | |
| 118 | // we only look for global variables |
| 119 | const Variable *var = tok->variable(); |
| 120 | if (!var || !(var->isGlobal() || var->isStatic())) |
| 121 | continue; |
| 122 | |
| 123 | const unsigned int varid(tok->varId()); |
| 124 | |
| 125 | // Token where throw occurs |
| 126 | const Token *throwToken = nullptr; |
| 127 | |
| 128 | // is there a throw after the deallocation? |
| 129 | const Token* const end2 = tok->scope()->bodyEnd; |
| 130 | for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) { |
| 131 | // Throw after delete -> Dead pointer |
| 132 | if (tok2->str() == "throw") { |
| 133 | if (printInconclusive) { // For inconclusive checking, throw directly. |
| 134 | deallocThrowError(tok2, tok->str()); |
| 135 | break; |
| 136 | } |
| 137 | throwToken = tok2; |
| 138 | } |
| 139 | |
| 140 | // Variable is assigned -> Bail out |
| 141 | else if (Token::Match(tok2, "%varid% =", varid)) { |
| 142 | if (throwToken) // For non-inconclusive checking, wait until we find an assignment to it. Otherwise we assume it is safe to leave a dead pointer. |
| 143 | deallocThrowError(throwToken, tok2->str()); |
| 144 | break; |
| 145 | } |
| 146 | // Variable passed to function. Assume it becomes assigned -> Bail out |
| 147 | else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference |
| 148 | break; |
no test coverage detected