STL: check for dangerous usage of string::c_str(). Ticket: #1116

This commit is contained in:
Daniel Marjamäki 2010-10-17 19:18:46 +02:00
parent 3faaa397e9
commit e54129fa8d
3 changed files with 73 additions and 1 deletions

View File

@ -918,3 +918,49 @@ void CheckStl::missingComparisonError(const Token *incrementToken1, const Token
}
void CheckStl::string_c_str()
{
// Try to detect common problems when using string::c_str()
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Locate executable scopes:
if (Token::Match(tok, ") const| {"))
{
std::set<unsigned int> localvar;
// scan through this executable scope:
unsigned int indentlevel = 0;
while (NULL != (tok = tok->next()))
{
if (tok->str() == "{")
++indentlevel;
else if (tok->str() == "}")
{
if (indentlevel <= 1)
break;
--indentlevel;
}
// Variable declarations..
else if (Token::Match(tok->previous(), "[;{}] std :: %type% %var% ;"))
localvar.insert(tok->tokAt(3)->varId());
else if (Token::Match(tok->previous(), "[;{}] %type% %var% ;"))
localvar.insert(tok->next()->varId());
// Invalid usage..
else if (Token::Match(tok, "throw %var% . c_str ( ) ;") &&
tok->next()->varId() > 0 &&
localvar.find(tok->next()->varId()) != localvar.end())
{
string_c_strError(tok);
}
}
}
}
}
void CheckStl::string_c_strError(const Token *tok)
{
reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str()");
}

View File

@ -55,6 +55,7 @@ public:
checkStl.pushback();
checkStl.stlBoundries();
checkStl.if_find();
checkStl.string_c_str();
// Style check
checkStl.size();
@ -129,6 +130,10 @@ public:
void missingComparison();
void missingComparisonError(const Token *incrementToken1, const Token *incrementToken2);
/** Check for common mistakes when using the function string::c_str() */
void string_c_str();
void string_c_strError(const Token *tok);
private:
/**
@ -163,6 +168,7 @@ private:
stlBoundriesError(0, "container");
if_findError(0, false);
if_findError(0, true);
string_c_strError(0);
sizeError(0);
eraseByValueError(0, "container", "iterator");
redundantIfRemoveError(0);
@ -183,7 +189,8 @@ private:
"* for vectors: using iterator/pointer after push_back has been used\n"
"* optimisation: use empty() instead of size() to guarantee fast code\n"
"* suspicious condition when using find\n"
"* redundant condition\n";
"* redundant condition\n"
"* common mistakes when using string::c_str()";
}
bool isStlContainer(const Token *tok);

View File

@ -98,6 +98,9 @@ private:
TEST_CASE(missingInnerComparison1);
TEST_CASE(missingInnerComparison2); // no FP when there is comparison
TEST_CASE(missingInnerComparison3); // no FP when there is iterator shadowing
// catch common problems when using the string::c_str() function
TEST_CASE(cstr);
}
void check(const std::string &code)
@ -1090,6 +1093,22 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
}
void cstr()
{
check("void f() {\n"
" std::string errmsg;\n"
" throw errmsg.c_str();\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
check("std::string f();\n"
"\n"
"void foo() {\n"
" const char *c = f().c_str();\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Dangerous usage of c_str()\n", errout.str());
}
};
REGISTER_TEST(TestStl)