51 logChecker(
"CheckExceptionSafety::destructors");
66 tok = tok->next()->link();
71 tok = tok->next()->link();
72 tok = tok->next()->link();
76 else if (tok->str() ==
"throw") {
88 "Class " + className +
" is not safe, destructor throws exception\n"
89 "The class " + className +
" is not safe because its destructor "
90 "throws an exception. If " + className +
" is used and an exception "
100 logChecker(
"CheckExceptionSafety::deallocThrow");
110 if (tok->str() !=
"delete")
117 if (!tok || tok == scope->
bodyEnd)
123 const Variable *var = tok->variable();
127 const unsigned int varid(tok->varId());
130 const Token *throwToken =
nullptr;
133 const Token*
const end2 = tok->
scope()->bodyEnd;
134 for (
const Token *tok2 = tok; tok2 != end2; tok2 = tok2->
next()) {
136 if (tok2->str() ==
"throw") {
137 if (printInconclusive) {
151 else if (
Token::Match(tok2,
"[,(] &| %varid% [,)]", varid))
175 logChecker(
"CheckExceptionSafety::checkRethrowCopy");
186 if (
Token::simpleMatch(tok,
"catch (") && tok->next()->link() && tok->next()->link()->next()) {
187 tok = tok->next()->link()->next()->link();
206 "Throwing a copy of the caught exception instead of rethrowing the original exception.\n"
207 "Rethrowing an exception with 'throw " + varname +
";' creates an unnecessary copy of '" + varname +
"'. "
208 "To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'.",
CWE398,
Certainty::normal);
219 logChecker(
"CheckExceptionSafety::checkCatchExceptionByValue");
238 "catchExceptionByValue",
"Exception should be caught by reference.\n"
239 "The exception is caught by value. It could be caught "
247 if (!recursive.insert(
function).second)
250 if (!function->functionScope)
253 for (
const Token *tok = function->functionScope->bodyStart->
next();
254 tok != function->functionScope->bodyEnd; tok = tok->
next()) {
257 if (tok->str() ==
"throw")
259 if (tok->function()) {
260 const Function * called = tok->function();
277 std::set<const Function *> recursive;
289 logChecker(
"CheckExceptionSafety::nothrowThrows");
299 if (function->isNoExcept() &&
300 (!function->noexceptArg || function->noexceptArg->str() ==
"true")) {
307 else if (function->isThrow() && !function->throwArg) {
314 else if (function->isAttributeNothrow()) {
336 logChecker(
"CheckExceptionSafety::unhandledExceptionSpecification");
345 if (tok->str() ==
"try")
347 if (tok->function()) {
348 const Function * called = tok->function();
362 const std::string str1(tok1 ? tok1->
str() :
"foo");
363 const std::list<const Token*> locationList = { tok1, tok2 };
365 "Unhandled exception specification when calling function " + str1 +
"().\n"
366 "Unhandled exception specification when calling function " + str1 +
"(). "
367 "Either use a try/catch around the function call, or add a exception specification for " + funcname +
"() also.",
CWE703,
Certainty::inconclusive);
375 logChecker(
"CheckExceptionSafety::rethrowNoCurrentException");
385 if (
Token::simpleMatch(function->functionScope->bodyStart->next(),
"try { throw ; } catch ("))
388 for (
const Token *tok = function->functionScope->bodyStart->
next();
389 tok != function->functionScope->bodyEnd; tok = tok->
next()) {
391 tok = tok->linkAt(1);
393 tok = tok->linkAt(1);
407 "Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow."
408 " If there is no current exception this calls std::terminate()."
409 " More: https://isocpp.org/wiki/faq/exceptions#throw-without-an-object",
static const CWE CWE398(398U)
static const Token * functionThrowsRecursive(const Function *function, std::set< const Function * > &recursive)
static const Token * functionThrows(const Function *function)
static const CWE CWE480(480U)
static const CWE CWE703(703U)
Check exception safety (exceptions shouldn't cause leaks nor corrupt data)
void unhandledExceptionSpecification()
Check for unhandled exception specification
void destructors()
Don't throw exceptions in destructors.
void nothrowThrows()
Check for functions that throw that shouldn't
void deallocThrowError(const Token *const tok, const std::string &varname)
void rethrowCopyError(const Token *const tok, const std::string &varname)
void noexceptThrowError(const Token *const tok)
void rethrowNoCurrentException()
Check for rethrow not from catch scope
void checkCatchExceptionByValue()
Check for exceptions that are caught by value instead of by reference
void catchExceptionByValueError(const Token *tok)
void deallocThrow()
deallocating memory and then throw (dead pointer)
void rethrowNoCurrentExceptionError(const Token *tok)
Rethrow without currently handled exception.
void checkRethrowCopy()
Don't rethrow a copy of the caught exception; use a bare throw instead.
void unhandledExceptionSpecificationError(const Token *const tok1, const Token *const tok2, const std::string &funcname)
Missing exception specification.
void destructorsError(const Token *const tok, const std::string &className)
Don't throw exceptions in destructors.
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
const std::string & name() const
const Scope * functionScope
scope of function body
const Token * throwArg
throw token
const Token * tokenDef
function name token in class definition
const Token * noexceptArg
noexcept token
bool isentrypoint(const std::string &func) const
Function * function
function info for this function
const Token * classDef
class/struct/union/namespace token
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
The token list that the TokenList generates is a linked-list of this class.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
const Token * tokAt(int index) const
void scope(const Scope *s)
Associate this token with given scope.
const Token * linkAt(int index) const
void variable(const Variable *v)
Associate this token with given variable.
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
void astParent(Token *tok)
const SymbolDatabase * getSymbolDatabase() const
Information about a member variable.
bool isClass() const
Is variable a user defined (or unknown) type.
bool isReference() const
Is reference variable.
bool isGlobal() const
Is variable global.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
@ error
Programming error.