void CheckExceptionSafety::deallocThrow() { if (!_settings->isEnabled("style")) return; const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); // Deallocate a global/member pointer and then throw exception // the pointer will be a dead pointer for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // only looking for delete now if (tok->str() != "delete") continue; // Check if this is something similar with: "delete p;" tok = tok->next(); if (Token::simpleMatch(tok, "[ ]")) tok = tok->tokAt(2); if (!tok) break; if (!Token::Match(tok, "%var% ;")) continue; const unsigned int varid(tok->varId()); if (varid == 0) continue; // we only look for global variables const Variable* var = symbolDatabase->getVariableFromVarId(varid); if (!var || !(var->isGlobal() || var->isStatic())) continue; // Token where throw occurs const Token *ThrowToken = 0; // is there a throw after the deallocation? const Token* const end2 = tok->scope()->classEnd; for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) { // Throw after delete -> Dead pointer if (tok2->str() == "throw") { if (_settings->inconclusive) { // For inconclusive checking, throw directly. deallocThrowError(tok2, tok->str()); break; } ThrowToken = tok2; } // Variable is assigned -> Bail out else if (Token::Match(tok2, "%varid% =", varid)) { if (ThrowToken) // For non-inconclusive checking, wait until we find an assignement to it. Otherwise we assume it is safe to leave a dead pointer. deallocThrowError(ThrowToken, tok2->str()); break; } // Variable passed to function. Assume it becomes assigned -> Bail out else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference break; } } }
void CheckExceptionSafety::deallocThrow() { const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase(); // Deallocate a global/member pointer and then throw exception // the pointer will be a dead pointer for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // only looking for delete now if (tok->str() != "delete") continue; // Check if this is something similar with: "delete p;" tok = tok->next(); if (Token::simpleMatch(tok, "[ ]")) tok = tok->tokAt(2); if (!tok) break; if (!Token::Match(tok, "%var% ;")) continue; const unsigned int varid(tok->varId()); if (varid == 0) continue; // we only look for global variables const Variable* var = symbolDatabase->getVariableFromVarId(varid); if (!var || !var->isGlobal()) continue; // indentlevel.. unsigned int indentlevel = 0; // Token where throw occurs const Token *ThrowToken = 0; // is there a throw after the deallocation? for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { if (tok2->str() == "{") ++indentlevel; else if (tok2->str() == "}") { if (indentlevel == 0) break; --indentlevel; } else if (tok2->str() == "throw") ThrowToken = tok2; // if the variable is not assigned after the throw then it // is assumed that it is not the intention that it is a dead pointer. else if (Token::Match(tok2, "%varid% =", varid)) { if (ThrowToken) deallocThrowError(ThrowToken, tok->str()); break; } } } }
void CheckExceptionSafety::deallocThrow() { for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (tok->str() != "delete") continue; // Check if this is something similar with: "delete p;" tok = tok->next(); if (Token::simpleMatch(tok, "[ ]")) tok = tok->tokAt(2); if (!tok) break; if (!Token::Match(tok, "%var% ;")) continue; const unsigned int varid(tok->varId()); if (varid == 0) continue; // is this variable a global variable? { bool globalVar = false; for (const Token *tok2 = _tokenizer->tokens(); tok2; tok2 = tok2->next()) { if (tok->varId() == varid) { globalVar = true; break; } if (tok2->str() == "class") { while (tok2 && tok2->str() != ";" && tok2->str() != "{") tok2 = tok2->next(); tok2 = tok2 ? tok2->next() : 0; if (!tok2) break; } if (tok2->str() == "{") { tok2 = tok2->link(); if (!tok2) break; } } if (!globalVar) continue; } // is there a throw after the deallocation? unsigned int indentlevel = 0; const Token *ThrowToken = 0; for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { if (tok2->str() == "{") ++indentlevel; else if (tok2->str() == "}") { if (indentlevel == 0) break; --indentlevel; } if (tok2->str() == "throw") ThrowToken = tok2; else if (Token::Match(tok2, "%varid% =", varid)) { if (ThrowToken) deallocThrowError(ThrowToken, tok->str()); break; } } } }