Fixed #3266 (False positive on dangerous usage of .c_str())
This commit is contained in:
parent
682aae3196
commit
4342fd254c
|
@ -1019,17 +1019,36 @@ void CheckStl::string_c_str()
|
||||||
tok->next()->varId() > 0 &&
|
tok->next()->varId() > 0 &&
|
||||||
localvar.find(tok->next()->varId()) != localvar.end()) {
|
localvar.find(tok->next()->varId()) != localvar.end()) {
|
||||||
string_c_strError(tok);
|
string_c_strError(tok);
|
||||||
} else if (Token::Match(tok, "return %var% . c_str ( ) ;") &&
|
} else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;") &&
|
||||||
tok->next()->varId() > 0 &&
|
tok->next()->varId() > 0 &&
|
||||||
localvar.find(tok->next()->varId()) != localvar.end()) {
|
pointers.find(tok->next()->varId()) != pointers.end()) {
|
||||||
string_c_strError(tok);
|
string_c_strError(tok);
|
||||||
|
} else if (Token::Match(tok, "[;{}] %var% = %var% (") &&
|
||||||
|
Token::simpleMatch(tok->tokAt(4)->link(), ") . c_str ( ) ;") &&
|
||||||
|
tok->next()->varId() > 0 &&
|
||||||
|
pointers.find(tok->next()->varId()) != pointers.end() &&
|
||||||
|
Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) {
|
||||||
|
string_c_strError(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This part is inconclusive as the return type of the function
|
||||||
|
// might convert it to another string class implicitly.
|
||||||
|
// TODO: As soon as the symbol database stores the return value
|
||||||
|
// of a function, we can check if it's const char* and output a real error.
|
||||||
|
if (!_settings->inconclusive)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Token::Match(tok, "return %var% . c_str ( ) ;") &&
|
||||||
|
tok->next()->varId() > 0 &&
|
||||||
|
localvar.find(tok->next()->varId()) != localvar.end()) {
|
||||||
|
string_c_strError(tok, true);
|
||||||
} else if (Token::Match(tok, "return %var% . str ( ) . c_str ( ) ;") &&
|
} else if (Token::Match(tok, "return %var% . str ( ) . c_str ( ) ;") &&
|
||||||
tok->next()->varId() > 0 &&
|
tok->next()->varId() > 0 &&
|
||||||
localvar.find(tok->next()->varId()) != localvar.end()) {
|
localvar.find(tok->next()->varId()) != localvar.end()) {
|
||||||
string_c_strError(tok);
|
string_c_strError(tok, true);
|
||||||
} else if (Token::simpleMatch(tok, "return std :: string (") &&
|
} else if (Token::simpleMatch(tok, "return std :: string (") &&
|
||||||
Token::simpleMatch(tok->tokAt(4)->link(), ") . c_str ( ) ;")) {
|
Token::simpleMatch(tok->tokAt(4)->link(), ") . c_str ( ) ;")) {
|
||||||
string_c_strError(tok);
|
string_c_strError(tok, true);
|
||||||
} else if (Token::simpleMatch(tok, "return (") &&
|
} else if (Token::simpleMatch(tok, "return (") &&
|
||||||
Token::simpleMatch(tok->next()->link(), ") . c_str ( ) ;")) {
|
Token::simpleMatch(tok->next()->link(), ") . c_str ( ) ;")) {
|
||||||
// Check for "+ localvar" or "+ std::string(" inside the bracket
|
// Check for "+ localvar" or "+ std::string(" inside the bracket
|
||||||
|
@ -1047,26 +1066,19 @@ void CheckStl::string_c_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_implicit_std_string)
|
if (is_implicit_std_string)
|
||||||
string_c_strError(tok);
|
string_c_strError(tok, true);
|
||||||
} else if (Token::Match(tok, "[;{}] %var% = %var% . str ( ) . c_str ( ) ;") &&
|
|
||||||
tok->next()->varId() > 0 &&
|
|
||||||
pointers.find(tok->next()->varId()) != pointers.end()) {
|
|
||||||
string_c_strError(tok);
|
|
||||||
} else if (Token::Match(tok, "[;{}] %var% = %var% (") &&
|
|
||||||
Token::simpleMatch(tok->tokAt(4)->link(), ") . c_str ( ) ;") &&
|
|
||||||
tok->next()->varId() > 0 &&
|
|
||||||
pointers.find(tok->next()->varId()) != pointers.end() &&
|
|
||||||
Token::findmatch(_tokenizer->tokens(), ("std :: string " + tok->strAt(3) + " (").c_str())) {
|
|
||||||
string_c_strError(tok);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckStl::string_c_strError(const Token *tok)
|
void CheckStl::string_c_strError(const Token* tok, bool is_inconlusive)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str()");
|
if (is_inconlusive)
|
||||||
|
reportInconclusiveError(tok, Severity::error, "stlcstr", "Possible dangerous usage of c_str()");
|
||||||
|
else
|
||||||
|
reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ public:
|
||||||
|
|
||||||
/** Check for common mistakes when using the function string::c_str() */
|
/** Check for common mistakes when using the function string::c_str() */
|
||||||
void string_c_str();
|
void string_c_str();
|
||||||
void string_c_strError(const Token *tok);
|
void string_c_strError(const Token *tok, bool is_inconlusive=false);
|
||||||
|
|
||||||
/** @brief %Check for use and copy auto pointer */
|
/** @brief %Check for use and copy auto pointer */
|
||||||
void checkAutoPointer();
|
void checkAutoPointer();
|
||||||
|
|
|
@ -122,6 +122,7 @@ private:
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.addEnabled("style");
|
settings.addEnabled("style");
|
||||||
settings.addEnabled("performance");
|
settings.addEnabled("performance");
|
||||||
|
settings.inconclusive = true;
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -1315,31 +1316,31 @@ private:
|
||||||
" std::string errmsg;\n"
|
" std::string errmsg;\n"
|
||||||
" return errmsg.c_str();\n"
|
" return errmsg.c_str();\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Possible dangerous usage of c_str()\n", errout.str());
|
||||||
|
|
||||||
check("const char *get_msg() {\n"
|
check("const char *get_msg() {\n"
|
||||||
" std::ostringstream errmsg;\n"
|
" std::ostringstream errmsg;\n"
|
||||||
" return errmsg.str().c_str();\n"
|
" return errmsg.str().c_str();\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Possible dangerous usage of c_str()\n", errout.str());
|
||||||
|
|
||||||
check("const char *get_msg() {\n"
|
check("const char *get_msg() {\n"
|
||||||
" std::string errmsg;\n"
|
" std::string errmsg;\n"
|
||||||
" return std::string(\"ERROR: \" + errmsg).c_str();\n"
|
" return std::string(\"ERROR: \" + errmsg).c_str();\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Possible dangerous usage of c_str()\n", errout.str());
|
||||||
|
|
||||||
check("const char *get_msg() {\n"
|
check("const char *get_msg() {\n"
|
||||||
" std::string errmsg;\n"
|
" std::string errmsg;\n"
|
||||||
" return (\"ERROR: \" + errmsg).c_str();\n"
|
" return (\"ERROR: \" + errmsg).c_str();\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Possible dangerous usage of c_str()\n", errout.str());
|
||||||
|
|
||||||
check("const char *get_msg() {\n"
|
check("const char *get_msg() {\n"
|
||||||
" std::string errmsg;\n"
|
" std::string errmsg;\n"
|
||||||
" return (\"ERROR: \" + std::string(\"crash me\")).c_str();\n"
|
" return (\"ERROR: \" + std::string(\"crash me\")).c_str();\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Dangerous usage of c_str()\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (error) Possible dangerous usage of c_str()\n", errout.str());
|
||||||
|
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" std::ostringstream errmsg;\n"
|
" std::ostringstream errmsg;\n"
|
||||||
|
|
Loading…
Reference in New Issue