forked from cppcheck-opensource/cppcheck
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcheckexceptionsafety.h
More file actions
175 lines (147 loc) · 7.58 KB
/
checkexceptionsafety.h
File metadata and controls
175 lines (147 loc) · 7.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2014 Daniel Marjamäki and Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#ifndef checkexceptionsafetyH
#define checkexceptionsafetyH
//---------------------------------------------------------------------------
#include "config.h"
#include "check.h"
/// @addtogroup Checks
/// @{
/**
* @brief %Check exception safety (exceptions shouldn't cause leaks nor corrupt data)
*
* The problem with these checks is that Cppcheck can't determine what the valid
* values are for variables. But in some cases (dead pointers) it can be determined
* that certain variable values are corrupt.
*/
class CPPCHECKLIB CheckExceptionSafety : public Check {
public:
/** This constructor is used when registering the CheckClass */
CheckExceptionSafety() : Check(myName()) {
}
/** This constructor is used when running checks. */
CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) {
}
/** Checks that uses the simplified token list */
void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
if (tokenizer->isC())
return;
CheckExceptionSafety checkExceptionSafety(tokenizer, settings, errorLogger);
checkExceptionSafety.destructors();
checkExceptionSafety.deallocThrow();
checkExceptionSafety.checkRethrowCopy();
checkExceptionSafety.checkCatchExceptionByValue();
checkExceptionSafety.nothrowThrows();
checkExceptionSafety.unhandledExceptionSpecification();
}
/** Don't throw exceptions in destructors */
void destructors();
/** deallocating memory and then throw (dead pointer) */
void deallocThrow();
/** Don't rethrow a copy of the caught exception; use a bare throw instead */
void checkRethrowCopy();
/** @brief %Check for exceptions that are caught by value instead of by reference */
void checkCatchExceptionByValue();
/** @brief %Check for functions that throw that shouldn't */
void nothrowThrows();
/** @brief %Check for unhandled exception specification */
void unhandledExceptionSpecification();
private:
/** Don't throw exceptions in destructors */
void destructorsError(const Token * const tok) {
reportError(tok, Severity::error, "exceptThrowInDestructor", "Exception thrown in destructor.");
}
void deallocThrowError(const Token * const tok, const std::string &varname) {
reportError(tok, Severity::warning, "exceptDeallocThrow", "Exception thrown in invalid state, '" +
varname + "' points at deallocated memory.");
}
void rethrowCopyError(const Token * const tok, const std::string &varname) {
reportError(tok, Severity::style, "exceptRethrowCopy",
"Throwing a copy of the caught exception instead of rethrowing the original exception.\n"
"Rethrowing an exception with 'throw " + varname + ";' creates an unnecessary copy of '" + varname + "'. "
"To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'.");
}
void catchExceptionByValueError(const Token *tok) {
reportError(tok, Severity::style,
"catchExceptionByValue", "Exception should be caught by reference.\n"
"The exception is caught by value. It could be caught "
"as a (const) reference which is usually recommended in C++.");
}
/** Don't throw exceptions in noexcept functions */
void noexceptThrowError(const Token * const tok) {
reportError(tok, Severity::error, "exceptThrowInNoexecptFunction", "Exception thrown in noexcept function.");
}
/** Don't throw exceptions in throw() functions */
void nothrowThrowError(const Token * const tok) {
reportError(tok, Severity::error, "exceptThrowInNoThrowFunction", "Exception thrown in throw() function.");
}
/** Don't throw exceptions in __attribute__((nothrow)) functions */
void nothrowAttributeThrowError(const Token * const tok) {
reportError(tok, Severity::error, "exceptThrowInAttributeNoThrowFunction", "Exception thrown in __attribute__((nothrow)) function.");
}
/** Don't throw exceptions in __declspec(nothrow) functions */
void nothrowDeclspecThrowError(const Token * const tok) {
reportError(tok, Severity::error, "exceptThrowInDeclspecNoThrowFunction", "Exception thrown in __declspec(nothrow) function.");
}
/** Missing exception specification */
void unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) {
std::string str1(tok1 ? tok1->str() : "foo");
std::list<const Token*> locationList;
locationList.push_back(tok1);
locationList.push_back(tok2);
reportError(locationList, Severity::style, "unhandledExceptionSpecification",
"Unhandled exception specification when calling function " + str1 + "().\n"
"Unhandled exception specification when calling function " + str1 + "(). "
"Either use a try/catch around the function call, or add a exception specification for " + funcname + "() also.", true);
}
/** Generate all possible errors (for --errorlist) */
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckExceptionSafety c(0, settings, errorLogger);
c.destructorsError(0);
c.deallocThrowError(0, "p");
c.rethrowCopyError(0, "varname");
c.catchExceptionByValueError(0);
c.noexceptThrowError(0);
c.nothrowThrowError(0);
c.nothrowAttributeThrowError(0);
c.nothrowDeclspecThrowError(0);
c.unhandledExceptionSpecificationError(0, 0, "funcname");
}
/** Short description of class (for --doc) */
static std::string myName() {
return "Exception Safety";
}
/** wiki formatted description of the class (for --doc) */
std::string classInfo() const {
return "Checking exception safety\n"
"* Throwing exceptions in destructors\n"
"* Throwing exception during invalid state\n"
"* Throwing a copy of a caught exception instead of rethrowing the original exception\n"
"* Exception caught by value instead of by reference\n"
"* Throwing exception in noexcept function\n"
"* Throwing exception in nothrow() function\n"
"* Throwing exception in __attribute__((nothrow)) function\n"
"* Throwing exception in __declspec(nothrow) function\n"
"* Unhandled exception specification when calling function foo()\n";
}
};
/// @}
//---------------------------------------------------------------------------
#endif // checkexceptionsafetyH