parent
d73a33d17e
commit
b04bf7396f
|
@ -380,6 +380,12 @@ bool isVariableDecl(const Token* tok)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isStlStringType(const Token* tok)
|
||||||
|
{
|
||||||
|
return Token::Match(tok, "std :: string|wstring|u16string|u32string !!::") ||
|
||||||
|
(Token::simpleMatch(tok, "std :: basic_string <") && !Token::simpleMatch(tok->linkAt(3), "> ::"));
|
||||||
|
}
|
||||||
|
|
||||||
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown)
|
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
|
|
@ -162,6 +162,7 @@ std::string astCanonicalType(const Token *expr);
|
||||||
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
|
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
|
||||||
|
|
||||||
bool isVariableDecl(const Token* tok);
|
bool isVariableDecl(const Token* tok);
|
||||||
|
bool isStlStringType(const Token* tok);
|
||||||
|
|
||||||
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown = false);
|
bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown = false);
|
||||||
|
|
||||||
|
|
|
@ -2009,6 +2009,18 @@ void CheckStl::string_c_str()
|
||||||
((Token::Match(tok->previous(), "%var% + %var% . c_str|data ( )") && tok->previous()->variable() && tok->previous()->variable()->isStlStringType()) ||
|
((Token::Match(tok->previous(), "%var% + %var% . c_str|data ( )") && tok->previous()->variable() && tok->previous()->variable()->isStlStringType()) ||
|
||||||
(Token::Match(tok->tokAt(-5), "%var% . c_str|data ( ) + %var%") && tok->tokAt(-5)->variable() && tok->tokAt(-5)->variable()->isStlStringType()))) {
|
(Token::Match(tok->tokAt(-5), "%var% . c_str|data ( ) + %var%") && tok->tokAt(-5)->variable() && tok->tokAt(-5)->variable()->isStlStringType()))) {
|
||||||
string_c_strConcat(tok);
|
string_c_strConcat(tok);
|
||||||
|
} else if (printPerformance && Token::simpleMatch(tok, "<<") && tok->astOperand2() && Token::simpleMatch(tok->astOperand2()->astOperand1(), ". c_str ( )")) {
|
||||||
|
const Token* str = tok->astOperand2()->astOperand1()->astOperand1();
|
||||||
|
if (Token::Match(str, "(|["))
|
||||||
|
str = str->previous();
|
||||||
|
if (str && ((str->variable() && str->variable()->isStlStringType()) ||
|
||||||
|
(str->function() && isStlStringType(str->function()->retDef)))) {
|
||||||
|
const Token* strm = tok;
|
||||||
|
while (Token::simpleMatch(strm, "<<"))
|
||||||
|
strm = strm->astOperand1();
|
||||||
|
if (strm && strm->variable() && strm->variable()->isStlType())
|
||||||
|
string_c_strStream(tok);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using c_str() to get the return value is only dangerous if the function returns a char*
|
// Using c_str() to get the return value is only dangerous if the function returns a char*
|
||||||
|
@ -2118,22 +2130,32 @@ void CheckStl::string_c_strParam(const Token* tok, nonneg int number)
|
||||||
|
|
||||||
void CheckStl::string_c_strConstructor(const Token* tok)
|
void CheckStl::string_c_strConstructor(const Token* tok)
|
||||||
{
|
{
|
||||||
std::string msg = "Constructing a std::string from the result of c_str() is slow and redundant.\nSolve that by directly passing the string.";
|
std::string msg = "Constructing a std::string from the result of c_str() is slow and redundant.\n"
|
||||||
|
"Constructing a std::string from const char* requires a call to strlen(). Solve that by directly passing the string.";
|
||||||
reportError(tok, Severity::performance, "stlcstrConstructor", msg, CWE704, Certainty::normal);
|
reportError(tok, Severity::performance, "stlcstrConstructor", msg, CWE704, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckStl::string_c_strAssignment(const Token* tok)
|
void CheckStl::string_c_strAssignment(const Token* tok)
|
||||||
{
|
{
|
||||||
std::string msg = "Assigning the result of c_str() to a std::string is slow and redundant.\nSolve that by directly assigning the string.";
|
std::string msg = "Assigning the result of c_str() to a std::string is slow and redundant.\n"
|
||||||
|
"Assigning a const char* to a std::string requires a call to strlen(). Solve that by directly assigning the string.";
|
||||||
reportError(tok, Severity::performance, "stlcstrAssignment", msg, CWE704, Certainty::normal);
|
reportError(tok, Severity::performance, "stlcstrAssignment", msg, CWE704, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckStl::string_c_strConcat(const Token* tok)
|
void CheckStl::string_c_strConcat(const Token* tok)
|
||||||
{
|
{
|
||||||
std::string msg = "Concatenating the result of c_str() and a std::string is slow and redundant.\nSolve that by directly concatenating the strings.";
|
std::string msg = "Concatenating the result of c_str() and a std::string is slow and redundant.\n"
|
||||||
|
"Concatenating a const char* with a std::string requires a call to strlen(). Solve that by directly concatenating the strings.";
|
||||||
reportError(tok, Severity::performance, "stlcstrConcat", msg, CWE704, Certainty::normal);
|
reportError(tok, Severity::performance, "stlcstrConcat", msg, CWE704, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckStl::string_c_strStream(const Token* tok)
|
||||||
|
{
|
||||||
|
std::string msg = "Passing the result of c_str() to a stream is slow and redundant.\n"
|
||||||
|
"Passing a const char* to a stream requires a call to strlen(). Solve that by directly passing the string.";
|
||||||
|
reportError(tok, Severity::performance, "stlcstrStream", msg, CWE704, Certainty::normal);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -196,6 +196,7 @@ private:
|
||||||
void string_c_strConstructor(const Token* tok);
|
void string_c_strConstructor(const Token* tok);
|
||||||
void string_c_strAssignment(const Token* tok);
|
void string_c_strAssignment(const Token* tok);
|
||||||
void string_c_strConcat(const Token* tok);
|
void string_c_strConcat(const Token* tok);
|
||||||
|
void string_c_strStream(const Token* tok);
|
||||||
|
|
||||||
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue);
|
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue);
|
||||||
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index);
|
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index);
|
||||||
|
|
|
@ -2187,7 +2187,7 @@ void Variable::evaluate(const Settings* settings)
|
||||||
strtype += "::" + typeToken->strAt(2);
|
strtype += "::" + typeToken->strAt(2);
|
||||||
setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != "...");
|
setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != "...");
|
||||||
setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::"));
|
setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::"));
|
||||||
setFlag(fIsStlString, isStlType() && (Token::Match(mTypeStartToken->tokAt(2), "string|wstring|u16string|u32string !!::") || (Token::simpleMatch(mTypeStartToken->tokAt(2), "basic_string <") && !Token::simpleMatch(mTypeStartToken->linkAt(3), "> ::"))));
|
setFlag(fIsStlString, ::isStlStringType(mTypeStartToken));
|
||||||
setFlag(fIsSmartPointer, lib->isSmartPointer(mTypeStartToken));
|
setFlag(fIsSmartPointer, lib->isSmartPointer(mTypeStartToken));
|
||||||
}
|
}
|
||||||
if (mAccess == AccessControl::Argument) {
|
if (mAccess == AccessControl::Argument) {
|
||||||
|
|
|
@ -4067,6 +4067,21 @@ private:
|
||||||
" const double* const QM_R__ buf(v.data() + i);\n"
|
" const double* const QM_R__ buf(v.data() + i);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("struct T { std::string g(); std::string a[1]; }\n" // #7515
|
||||||
|
"void f(std::stringstream& strm, const std::string& s, T& t) {\n"
|
||||||
|
" strm << s.c_str();\n"
|
||||||
|
" strm << \"abc\" << s.c_str();\n"
|
||||||
|
" strm << \"abc\" << s.c_str() << \"def\";\n"
|
||||||
|
" strm << \"abc\" << t.g().c_str() << \"def\";\n"
|
||||||
|
" strm << t.a[0].c_str();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (performance) Passing the result of c_str() to a stream is slow and redundant.\n"
|
||||||
|
"[test.cpp:4]: (performance) Passing the result of c_str() to a stream is slow and redundant.\n"
|
||||||
|
"[test.cpp:5]: (performance) Passing the result of c_str() to a stream is slow and redundant.\n"
|
||||||
|
"[test.cpp:6]: (performance) Passing the result of c_str() to a stream is slow and redundant.\n"
|
||||||
|
"[test.cpp:7]: (performance) Passing the result of c_str() to a stream is slow and redundant.\n",
|
||||||
|
errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void uselessCalls() {
|
void uselessCalls() {
|
||||||
|
|
Loading…
Reference in New Issue