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 : : #include "checkexceptionsafety.h"
21 : : #include "symboldatabase.h"
22 : : #include "token.h"
23 : :
24 : : //---------------------------------------------------------------------------
25 : :
26 : : // Register CheckExceptionSafety..
27 : : namespace {
28 : 45 : CheckExceptionSafety instance;
29 : : }
30 : :
31 : :
32 : : //---------------------------------------------------------------------------
33 : :
34 : 1771 : void CheckExceptionSafety::destructors()
35 : : {
36 : 1771 : const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
37 : :
38 : : // Perform check..
39 : 1771 : const std::size_t functions = symbolDatabase->functionScopes.size();
40 [ + + ]: 3542 : for (std::size_t i = 0; i < functions; ++i) {
41 : 1771 : const Scope * scope = symbolDatabase->functionScopes[i];
42 : 1771 : const Function * j = scope->function;
43 [ + + ]: 1771 : if (j) {
44 : : // only looking for destructors
45 [ + + ]: 1726 : if (j->type == Function::eDestructor) {
46 : : // Inspect this destructor..
47 [ + + ]: 630 : for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
48 : : // Skip try blocks
49 [ + + ]: 495 : if (Token::simpleMatch(tok, "try {")) {
50 : 45 : tok = tok->next()->link();
51 : : }
52 : :
53 : : // throw found within a destructor
54 [ + + ]: 495 : if (tok->str() == "throw") {
55 : 90 : destructorsError(tok);
56 : 90 : break;
57 : : }
58 : : }
59 : : }
60 : : }
61 : : }
62 : 1771 : }
63 : :
64 : :
65 : :
66 : :
67 : 1771 : void CheckExceptionSafety::deallocThrow()
68 : : {
69 [ + - ][ + - ]: 1771 : if (!_settings->isEnabled("warning"))
[ + - ][ + + ]
70 : 1771 : return;
71 : :
72 : 1035 : const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
73 : :
74 : : // Deallocate a global/member pointer and then throw exception
75 : : // the pointer will be a dead pointer
76 : 1035 : const std::size_t functions = symbolDatabase->functionScopes.size();
77 [ + + ]: 2070 : for (std::size_t i = 0; i < functions; ++i) {
78 : 1035 : const Scope * scope = symbolDatabase->functionScopes[i];
79 [ + + ]: 20025 : for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
80 : : // only looking for delete now
81 [ + + ]: 18990 : if (tok->str() != "delete")
82 : 18720 : continue;
83 : :
84 : : // Check if this is something similar with: "delete p;"
85 : 270 : tok = tok->next();
86 [ - + ]: 270 : if (Token::simpleMatch(tok, "[ ]"))
87 : 0 : tok = tok->tokAt(2);
88 [ - + ]: 270 : if (!tok)
89 : 0 : break;
90 [ - + ]: 270 : if (!Token::Match(tok, "%var% ;"))
91 : 0 : continue;
92 : :
93 : : // we only look for global variables
94 : 270 : const Variable *var = tok->variable();
95 [ + - ][ + + ]: 270 : if (!var || !(var->isGlobal() || var->isStatic()))
[ + + ][ + + ]
96 : 45 : continue;
97 : :
98 : 225 : const unsigned int varid(tok->varId());
99 : :
100 : : // Token where throw occurs
101 : 225 : const Token *ThrowToken = 0;
102 : :
103 : : // is there a throw after the deallocation?
104 : 225 : const Token* const end2 = tok->scope()->classEnd;
105 [ + + ]: 1665 : for (const Token *tok2 = tok; tok2 != end2; tok2 = tok2->next()) {
106 : : // Throw after delete -> Dead pointer
107 [ + + ]: 1620 : if (tok2->str() == "throw") {
108 [ + + ]: 180 : if (_settings->inconclusive) { // For inconclusive checking, throw directly.
109 : 45 : deallocThrowError(tok2, tok->str());
110 : 45 : break;
111 : : }
112 : 135 : ThrowToken = tok2;
113 : : }
114 : :
115 : : // Variable is assigned -> Bail out
116 [ + + ]: 1440 : else if (Token::Match(tok2, "%varid% =", varid)) {
117 [ + - ]: 90 : 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.
118 : 90 : deallocThrowError(ThrowToken, tok2->str());
119 : 90 : break;
120 : : }
121 : : // Variable passed to function. Assume it becomes assigned -> Bail out
122 [ + + ]: 1350 : else if (Token::Match(tok2, "[,(] &| %varid% [,)]", varid)) // TODO: No bailout if passed by value or as const reference
123 : 45 : break;
124 : : }
125 : : }
126 : : }
127 : : }
128 : :
129 : : //---------------------------------------------------------------------------
130 : : // catch(const exception & err)
131 : : // {
132 : : // throw err; // <- should be just "throw;"
133 : : // }
134 : : //---------------------------------------------------------------------------
135 : 1771 : void CheckExceptionSafety::checkRethrowCopy()
136 : : {
137 [ + - ][ + - ]: 1771 : if (!_settings->isEnabled("style"))
[ + - ][ + + ]
138 : 1771 : return;
139 : :
140 : 1035 : const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
141 : :
142 [ + + ]: 4815 : for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
143 [ + + ]: 3780 : if (i->type != Scope::eCatch)
144 : 3060 : continue;
145 : :
146 : 720 : const unsigned int varid = i->classStart->tokAt(-2)->varId();
147 [ + + ]: 720 : if (varid) {
148 [ + - ][ + + ]: 4005 : for (const Token* tok = i->classStart->next(); tok && tok != i->classEnd; tok = tok->next()) {
[ + + ]
149 [ + + ][ + - ]: 3330 : if (Token::simpleMatch(tok, "catch (") && tok->next()->link() && tok->next()->link()->next()) // Don't check inner catch - it is handled in another iteration of outer loop.
[ + - ][ + + ]
150 : 90 : tok = tok->next()->link()->next()->link();
151 [ + + ]: 3240 : else if (Token::Match(tok, "throw %varid% ;", varid))
152 : 180 : rethrowCopyError(tok, tok->strAt(1));
153 : : }
154 : : }
155 : : }
156 : : }
157 : :
158 : : //---------------------------------------------------------------------------
159 : : // try {} catch (std::exception err) {} <- Should be "std::exception& err"
160 : : //---------------------------------------------------------------------------
161 : 1771 : void CheckExceptionSafety::checkCatchExceptionByValue()
162 : : {
163 [ + - ][ + - ]: 1771 : if (!_settings->isEnabled("style"))
[ + - ][ + + ]
164 : 1771 : return;
165 : :
166 : 1035 : const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
167 : :
168 [ + + ]: 4815 : for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
169 [ + + ]: 3780 : if (i->type != Scope::eCatch)
170 : 3060 : continue;
171 : :
172 : : // Find a pass-by-value declaration in the catch(), excluding basic types
173 : : // e.g. catch (std::exception err)
174 : 720 : const Variable *var = i->classStart->tokAt(-2)->variable();
175 [ + + ][ + + ]: 720 : if (var && var->isClass() && !var->isPointer() && !var->isReference())
[ + - ][ + - ]
[ + + ]
176 : 90 : catchExceptionByValueError(i->classDef);
177 : : }
178 [ + - ][ + - ]: 135 : }
|