Branch data Line data Source code
1 : : /*
2 : : * Cppcheck - A tool for static C/C++ code analysis
3 : : * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
4 : : *
5 : : * This program is free software: you can redistribute it and/or modify
6 : : * it under the terms of the GNU General Public License as published by
7 : : * the Free Software Foundation, either version 3 of the License, or
8 : : * (at your option) any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : * GNU General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License
16 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : : */
18 : :
19 : : //---------------------------------------------------------------------------
20 : : #ifndef checkexceptionsafetyH
21 : : #define checkexceptionsafetyH
22 : : //---------------------------------------------------------------------------
23 : :
24 : : #include "config.h"
25 : : #include "check.h"
26 : : #include "settings.h"
27 : :
28 : : class Token;
29 : :
30 : : /// @addtogroup Checks
31 : : /// @{
32 : :
33 : :
34 : :
35 : : /**
36 : : * @brief %Check exception safety (exceptions shouldn't cause leaks nor corrupt data)
37 : : *
38 : : * The problem with these checks is that Cppcheck can't determine what the valid
39 : : * values are for variables. But in some cases (dead pointers) it can be determined
40 : : * that certain variable values are corrupt.
41 : : */
42 : :
43 [ - + ]: 2896 : class CPPCHECKLIB CheckExceptionSafety : public Check {
44 : : public:
45 : : /** This constructor is used when registering the CheckClass */
46 [ + - ]: 45 : CheckExceptionSafety() : Check(myName())
47 : 45 : { }
48 : :
49 : : /** This constructor is used when running checks. */
50 : 2851 : CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
51 [ + - ]: 2851 : : Check(myName(), tokenizer, settings, errorLogger)
52 : 2851 : { }
53 : :
54 : : /** Checks that uses the simplified token list */
55 : 1771 : void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
56 [ - + ]: 1771 : if (tokenizer->isC())
57 : 1771 : return;
58 : :
59 : 1771 : CheckExceptionSafety checkExceptionSafety(tokenizer, settings, errorLogger);
60 [ + - ]: 1771 : checkExceptionSafety.destructors();
61 [ + - ]: 1771 : checkExceptionSafety.deallocThrow();
62 [ + - ]: 1771 : checkExceptionSafety.checkRethrowCopy();
63 [ + - ]: 1771 : checkExceptionSafety.checkCatchExceptionByValue();
64 : : }
65 : :
66 : : /** Don't throw exceptions in destructors */
67 : : void destructors();
68 : :
69 : : /** deallocating memory and then throw (dead pointer) */
70 : : void deallocThrow();
71 : :
72 : : /** Don't rethrow a copy of the caught exception; use a bare throw instead */
73 : : void checkRethrowCopy();
74 : :
75 : : /** @brief %Check for exceptions that are caught by value instead of by reference */
76 : : void checkCatchExceptionByValue();
77 : :
78 : : private:
79 : : /** Don't throw exceptions in destructors */
80 : 135 : void destructorsError(const Token * const tok) {
81 [ + - ][ + - ]: 135 : reportError(tok, Severity::error, "exceptThrowInDestructor", "Exception thrown in destructor.");
[ + - ][ + - ]
[ + - ]
82 : 135 : }
83 : :
84 : 180 : void deallocThrowError(const Token * const tok, const std::string &varname) {
85 : : reportError(tok, Severity::warning, "exceptDeallocThrow", "Exception thrown in invalid state, '" +
86 [ + - ][ + - ]: 180 : varname + "' points at deallocated memory.");
[ + - ][ + - ]
[ + - ]
87 : 180 : }
88 : :
89 : 225 : void rethrowCopyError(const Token * const tok, const std::string &varname) {
90 : : reportError(tok, Severity::style, "exceptRethrowCopy",
91 : : "Throwing a copy of the caught exception instead of rethrowing the original exception.\n"
92 : : "Rethrowing an exception with 'throw " + varname + ";' creates an unnecessary copy of '" + varname + "'. "
93 [ + - ][ + - ]: 225 : "To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'.");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
94 : 225 : }
95 : :
96 : 135 : void catchExceptionByValueError(const Token *tok) {
97 : : reportError(tok, Severity::style,
98 : : "catchExceptionByValue", "Exception should be caught by reference.\n"
99 : : "The exception is caught by value. It could be caught "
100 [ + - ][ + - ]: 135 : "as a (const) reference which is usually recommended in C++.");
[ + - ][ + - ]
[ + - ]
101 : 135 : }
102 : :
103 : : /** Generate all possible errors (for --errorlist) */
104 : 45 : void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
105 : 45 : CheckExceptionSafety c(0, settings, errorLogger);
106 [ + - ]: 45 : c.destructorsError(0);
107 [ + - ][ + - ]: 45 : c.deallocThrowError(0, "p");
[ + - ]
108 [ + - ][ + - ]: 45 : c.rethrowCopyError(0, "varname");
[ + - ]
109 [ + - ]: 45 : c.catchExceptionByValueError(0);
110 : 45 : }
111 : :
112 : : /** Short description of class (for --doc) */
113 : 2896 : static std::string myName() {
114 [ + - ]: 2896 : return "Exception Safety";
115 : : }
116 : :
117 : : /** wiki formatted description of the class (for --doc) */
118 : 45 : std::string classInfo() const {
119 : : return "Checking exception safety\n"
120 : : "* Throwing exceptions in destructors\n"
121 : : "* Throwing exception during invalid state\n"
122 : : "* Throwing a copy of a caught exception instead of rethrowing the original exception\n"
123 [ + - ]: 45 : "* Exception caught by value instead of by reference\n";
124 : : }
125 : : };
126 : : /// @}
127 : : //---------------------------------------------------------------------------
128 : : #endif
|