Skip to content

Commit 8a494cf

Browse files
committed
Fixed cppcheck-opensource#2388 (Use throw without argument to rethrow exceptions)
1 parent 95e917b commit 8a494cf

3 files changed

Lines changed: 91 additions & 1 deletion

File tree

lib/checkexceptionsafety.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,32 @@ void CheckExceptionSafety::deallocThrow()
167167
}
168168
}
169169

170+
//---------------------------------------------------------------------------
171+
// catch(const exception & err)
172+
// {
173+
// throw err; // <- should be just "throw;"
174+
// }
175+
//---------------------------------------------------------------------------
176+
void CheckExceptionSafety::checkRethrowCopy()
177+
{
178+
if (!_settings->_checkCodingStyle)
179+
return;
180+
const char catchPattern[] = "catch ( const| %type% &|*| %var% ) { %any%";
181+
182+
const Token *tok = Token::findmatch(_tokenizer->tokens(), catchPattern);
183+
while (tok)
184+
{
185+
const Token *startBlockTok = tok->next()->link()->next();
186+
const Token *endBlockTok = startBlockTok->link();
187+
const unsigned int varid = startBlockTok->tokAt(-2)->varId();
188+
189+
const Token* rethrowTok = Token::findmatch(startBlockTok, "throw %varid%", endBlockTok, varid);
190+
if (rethrowTok)
191+
{
192+
rethrowCopyError(rethrowTok);
193+
}
194+
195+
tok = Token::findmatch(endBlockTok->next(), catchPattern);
196+
}
197+
}
170198

lib/checkexceptionsafety.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class CheckExceptionSafety : public Check
5757
CheckExceptionSafety checkExceptionSafety(tokenizer, settings, errorLogger);
5858
checkExceptionSafety.destructors();
5959
checkExceptionSafety.deallocThrow();
60+
checkExceptionSafety.checkRethrowCopy();
6061
}
6162

6263
/** Don't throw exceptions in destructors */
@@ -65,6 +66,9 @@ class CheckExceptionSafety : public Check
6566
/** deallocating memory and then throw (dead pointer) */
6667
void deallocThrow();
6768

69+
/** Don't rethrow a copy of the caught exception; use a bare throw instead */
70+
void checkRethrowCopy();
71+
6872
private:
6973
/** Don't throw exceptions in destructors */
7074
void destructorsError(const Token * const tok)
@@ -77,12 +81,20 @@ class CheckExceptionSafety : public Check
7781
reportError(tok, Severity::error, "exceptDeallocThrow", "Throwing exception in invalid state, " + varname + " points at deallocated memory");
7882
}
7983

84+
void rethrowCopyError(const Token * const tok)
85+
{
86+
reportError(tok, Severity::style, "exceptRethrowCopy",
87+
"Throwing a copy of the caught exception instead of rethrowing the original exception\n"
88+
"To rethrow the caught exception without unnecessary copying or slicing, use a bare 'throw;'. ");
89+
}
90+
8091
/** Generate all possible errors (for --errorlist) */
8192
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
8293
{
8394
CheckExceptionSafety c(0, settings, errorLogger);
8495
c.destructorsError(0);
8596
c.deallocThrowError(0, "p");
97+
c.rethrowCopyError(0);
8698
}
8799

88100
/** Short description of class (for --doc) */
@@ -96,7 +108,8 @@ class CheckExceptionSafety : public Check
96108
{
97109
return "Checking exception safety\n"
98110
"* Throwing exceptions in destructors\n"
99-
"* Throwing exception during invalid state";
111+
"* Throwing exception during invalid state\n"
112+
"* Throwing a copy of a caught exception instead of rethrowing the original exception";
100113
}
101114
};
102115
/// @}

test/testexceptionsafety.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class TestExceptionSafety : public TestFixture
3737
TEST_CASE(destructors);
3838
TEST_CASE(deallocThrow1);
3939
TEST_CASE(deallocThrow2);
40+
TEST_CASE(rethrowCopy1);
41+
TEST_CASE(rethrowCopy2);
42+
TEST_CASE(rethrowCopy3);
4043
}
4144

4245
void check(const std::string &code)
@@ -90,6 +93,52 @@ class TestExceptionSafety : public TestFixture
9093
"}\n");
9194
ASSERT_EQUALS("", errout.str());
9295
}
96+
97+
void rethrowCopy1()
98+
{
99+
check("void f() {\n"
100+
" try\n"
101+
" {\n"
102+
" foo();\n"
103+
" }\n"
104+
" catch(const exception& err)\n"
105+
" {\n"
106+
" throw err;\n"
107+
" }\n"
108+
"}\n");
109+
ASSERT_EQUALS("[test.cpp:8]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception\n", errout.str());
110+
}
111+
112+
void rethrowCopy2()
113+
{
114+
check("void f() {\n"
115+
" try\n"
116+
" {\n"
117+
" foo();\n"
118+
" }\n"
119+
" catch(exception err)\n"
120+
" {\n"
121+
" throw err;\n"
122+
" }\n"
123+
"}\n");
124+
ASSERT_EQUALS("[test.cpp:8]: (style) Throwing a copy of the caught exception instead of rethrowing the original exception\n", errout.str());
125+
}
126+
127+
void rethrowCopy3()
128+
{
129+
check("void f() {\n"
130+
" try\n"
131+
" {\n"
132+
" foo();\n"
133+
" }\n"
134+
" catch(exception err)\n"
135+
" {\n"
136+
" exception err2;\n"
137+
" throw err2;\n"
138+
" }\n"
139+
"}\n");
140+
ASSERT_EQUALS("", errout.str());
141+
}
93142
};
94143

95144
REGISTER_TEST(TestExceptionSafety)

0 commit comments

Comments
 (0)