Checkstring fixes (#1783)
* teststring.cpp: Fix ternary syntax in tests * stringLiteralWrite: Add tests wide character and utf16 strings * suspiciousStringCompare: Add test with wide character string * strPlusChar: Handle wide characters * incorrectStringCompare: Add test with wide string * Suspicious string compare: suggest wcscmp for wide strings * deadStrcmp: Extend to handle wide strings * sprintfOverlappingData: Print name of strcmp function * Conversion of char literal to boolean, add wide character tests * Conversion of char literal to boolean, fix ternary
This commit is contained in:
parent
16ebb90b32
commit
295153df72
|
@ -213,7 +213,7 @@ void CheckString::checkSuspiciousStringCompare()
|
||||||
const bool ischar(litTok->tokType() == Token::eChar);
|
const bool ischar(litTok->tokType() == Token::eChar);
|
||||||
if (litTok->tokType() == Token::eString) {
|
if (litTok->tokType() == Token::eString) {
|
||||||
if (mTokenizer->isC() || (var && var->isArrayOrPointer()))
|
if (mTokenizer->isC() || (var && var->isArrayOrPointer()))
|
||||||
suspiciousStringCompareError(tok, varname);
|
suspiciousStringCompareError(tok, varname, litTok->isLong());
|
||||||
} else if (ischar && var && var->isPointer()) {
|
} else if (ischar && var && var->isPointer()) {
|
||||||
suspiciousStringCompareError_char(tok, varname);
|
suspiciousStringCompareError_char(tok, varname);
|
||||||
}
|
}
|
||||||
|
@ -221,10 +221,11 @@ void CheckString::checkSuspiciousStringCompare()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckString::suspiciousStringCompareError(const Token* tok, const std::string& var)
|
void CheckString::suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong)
|
||||||
{
|
{
|
||||||
|
const std::string cmpFunc = isLong ? "wcscmp" : "strcmp";
|
||||||
reportError(tok, Severity::warning, "literalWithCharPtrCompare",
|
reportError(tok, Severity::warning, "literalWithCharPtrCompare",
|
||||||
"$symbol:" + var + "\nString literal compared with variable '$symbol'. Did you intend to use strcmp() instead?", CWE595, false);
|
"$symbol:" + var + "\nString literal compared with variable '$symbol'. Did you intend to use " + cmpFunc + "() instead?", CWE595, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckString::suspiciousStringCompareError_char(const Token* tok, const std::string& var)
|
void CheckString::suspiciousStringCompareError_char(const Token* tok, const std::string& var)
|
||||||
|
@ -240,7 +241,7 @@ void CheckString::suspiciousStringCompareError_char(const Token* tok, const std:
|
||||||
|
|
||||||
static bool isChar(const Variable* var)
|
static bool isChar(const Variable* var)
|
||||||
{
|
{
|
||||||
return (var && !var->isPointer() && !var->isArray() && var->typeStartToken()->str() == "char");
|
return (var && !var->isPointer() && !var->isArray() && (var->typeStartToken()->str() == "char" || var->typeStartToken()->str() == "wchar_t"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckString::strPlusChar()
|
void CheckString::strPlusChar()
|
||||||
|
@ -260,7 +261,12 @@ void CheckString::strPlusChar()
|
||||||
|
|
||||||
void CheckString::strPlusCharError(const Token *tok)
|
void CheckString::strPlusCharError(const Token *tok)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic. A value of type 'char' is added to a string literal.", CWE665, false);
|
std::string charType = "char";
|
||||||
|
if (tok && tok->astOperand2() && tok->astOperand2()->variable())
|
||||||
|
charType = tok->astOperand2()->variable()->typeStartToken()->str();
|
||||||
|
else if (tok && tok->astOperand2() && tok->astOperand2()->tokType() == Token::eChar && tok->astOperand2()->isLong())
|
||||||
|
charType = "wchar_t";
|
||||||
|
reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic. A value of type '" + charType +"' is added to a string literal.", CWE665, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -309,7 +315,8 @@ void CheckString::checkIncorrectStringCompare()
|
||||||
incorrectStringBooleanError(tok->next(), tok->strAt(1));
|
incorrectStringBooleanError(tok->next(), tok->strAt(1));
|
||||||
} else if (Token::Match(tok, "if|while ( %str%|%char% )") && !tok->tokAt(2)->getValue(0)) {
|
} else if (Token::Match(tok, "if|while ( %str%|%char% )") && !tok->tokAt(2)->getValue(0)) {
|
||||||
incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2));
|
incorrectStringBooleanError(tok->tokAt(2), tok->strAt(2));
|
||||||
}
|
} else if (tok->str() == "?" && Token::Match(tok->astOperand1(), "%str%|%char%"))
|
||||||
|
incorrectStringBooleanError(tok->astOperand1(), tok->astOperand1()->str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,9 +387,9 @@ void CheckString::overlappingStrcmp()
|
||||||
|
|
||||||
for (const Token *eq0 : equals0) {
|
for (const Token *eq0 : equals0) {
|
||||||
for (const Token * ne0 : notEquals0) {
|
for (const Token * ne0 : notEquals0) {
|
||||||
if (!Token::simpleMatch(eq0->previous(), "strcmp ("))
|
if (!Token::Match(eq0->previous(), "strcmp|wcscmp ("))
|
||||||
continue;
|
continue;
|
||||||
if (!Token::simpleMatch(ne0->previous(), "strcmp ("))
|
if (!Token::Match(ne0->previous(), "strcmp|wcscmp ("))
|
||||||
continue;
|
continue;
|
||||||
const std::vector<const Token *> args1 = getArguments(eq0->previous());
|
const std::vector<const Token *> args1 = getArguments(eq0->previous());
|
||||||
const std::vector<const Token *> args2 = getArguments(ne0->previous());
|
const std::vector<const Token *> args2 = getArguments(ne0->previous());
|
||||||
|
@ -445,20 +452,22 @@ void CheckString::sprintfOverlappingData()
|
||||||
true,
|
true,
|
||||||
false);
|
false);
|
||||||
if (same) {
|
if (same) {
|
||||||
sprintfOverlappingDataError(args[argnr], args[argnr]->expressionString());
|
sprintfOverlappingDataError(tok, args[argnr], args[argnr]->expressionString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckString::sprintfOverlappingDataError(const Token *tok, const std::string &varname)
|
void CheckString::sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname)
|
||||||
{
|
{
|
||||||
|
const std::string func = funcTok ? funcTok->str() : "s[n]printf";
|
||||||
|
|
||||||
reportError(tok, Severity::error, "sprintfOverlappingData",
|
reportError(tok, Severity::error, "sprintfOverlappingData",
|
||||||
"$symbol:" + varname + "\n"
|
"$symbol:" + varname + "\n"
|
||||||
"Undefined behavior: Variable '$symbol' is used as parameter and destination in s[n]printf().\n"
|
"Undefined behavior: Variable '$symbol' is used as parameter and destination in " + func + "().\n" +
|
||||||
"The variable '$symbol' is used both as a parameter and as destination in "
|
"The variable '$symbol' is used both as a parameter and as destination in " +
|
||||||
"s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) "
|
func + "(). The origin and destination buffers overlap. Quote from glibc (C-library) "
|
||||||
"documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
|
"documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
|
||||||
"\"If copying takes place between objects that overlap as a result of a call "
|
"\"If copying takes place between objects that overlap as a result of a call "
|
||||||
"to sprintf() or snprintf(), the results are undefined.\"", CWE628, false);
|
"to sprintf() or snprintf(), the results are undefined.\"", CWE628, false);
|
||||||
|
|
|
@ -86,13 +86,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void stringLiteralWriteError(const Token *tok, const Token *strValue);
|
void stringLiteralWriteError(const Token *tok, const Token *strValue);
|
||||||
void sprintfOverlappingDataError(const Token *tok, const std::string &varname);
|
void sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname);
|
||||||
void strPlusCharError(const Token *tok);
|
void strPlusCharError(const Token *tok);
|
||||||
void incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string);
|
void incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string);
|
||||||
void incorrectStringBooleanError(const Token *tok, const std::string& string);
|
void incorrectStringBooleanError(const Token *tok, const std::string& string);
|
||||||
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
void suspiciousStringCompareError(const Token* tok, const std::string& var);
|
void suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong);
|
||||||
void suspiciousStringCompareError_char(const Token* tok, const std::string& var);
|
void suspiciousStringCompareError_char(const Token* tok, const std::string& var);
|
||||||
void overlappingStrcmpError(const Token* eq0, const Token *ne0);
|
void overlappingStrcmpError(const Token* eq0, const Token *ne0);
|
||||||
|
|
||||||
|
@ -100,10 +100,10 @@ private:
|
||||||
CheckString c(nullptr, settings, errorLogger);
|
CheckString c(nullptr, settings, errorLogger);
|
||||||
|
|
||||||
c.stringLiteralWriteError(nullptr, nullptr);
|
c.stringLiteralWriteError(nullptr, nullptr);
|
||||||
c.sprintfOverlappingDataError(nullptr, "varname");
|
c.sprintfOverlappingDataError(nullptr, nullptr, "varname");
|
||||||
c.strPlusCharError(nullptr);
|
c.strPlusCharError(nullptr);
|
||||||
c.incorrectStringCompareError(nullptr, "substr", "\"Hello World\"");
|
c.incorrectStringCompareError(nullptr, "substr", "\"Hello World\"");
|
||||||
c.suspiciousStringCompareError(nullptr, "foo");
|
c.suspiciousStringCompareError(nullptr, "foo", false);
|
||||||
c.suspiciousStringCompareError_char(nullptr, "foo");
|
c.suspiciousStringCompareError_char(nullptr, "foo");
|
||||||
c.incorrectStringBooleanError(nullptr, "\"Hello World\"");
|
c.incorrectStringBooleanError(nullptr, "\"Hello World\"");
|
||||||
c.incorrectStringBooleanError(nullptr, "\'x\'");
|
c.incorrectStringBooleanError(nullptr, "\'x\'");
|
||||||
|
|
|
@ -44,11 +44,14 @@ private:
|
||||||
TEST_CASE(strPlusChar1); // "/usr" + '/'
|
TEST_CASE(strPlusChar1); // "/usr" + '/'
|
||||||
TEST_CASE(strPlusChar2); // "/usr" + ch
|
TEST_CASE(strPlusChar2); // "/usr" + ch
|
||||||
TEST_CASE(strPlusChar3); // ok: path + "/sub" + '/'
|
TEST_CASE(strPlusChar3); // ok: path + "/sub" + '/'
|
||||||
|
TEST_CASE(strPlusChar4); // L"/usr" + L'/'
|
||||||
|
|
||||||
|
TEST_CASE(snprintf1); // Dangerous usage of snprintf
|
||||||
TEST_CASE(sprintf1); // Dangerous usage of sprintf
|
TEST_CASE(sprintf1); // Dangerous usage of sprintf
|
||||||
TEST_CASE(sprintf2);
|
TEST_CASE(sprintf2);
|
||||||
TEST_CASE(sprintf3);
|
TEST_CASE(sprintf3);
|
||||||
TEST_CASE(sprintf4); // struct member
|
TEST_CASE(sprintf4); // struct member
|
||||||
|
TEST_CASE(wsprintf1); // Dangerous usage of wsprintf
|
||||||
|
|
||||||
TEST_CASE(incorrectStringCompare);
|
TEST_CASE(incorrectStringCompare);
|
||||||
|
|
||||||
|
@ -105,6 +108,18 @@ private:
|
||||||
" foo_FP1(s);\n"
|
" foo_FP1(s);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" wchar_t *abc = L\"abc\";\n"
|
||||||
|
" abc[0] = u'a';\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char16_t *abc = u\"abc\";\n"
|
||||||
|
" abc[0] = 'a';\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void alwaysTrueFalseStringCompare() {
|
void alwaysTrueFalseStringCompare() {
|
||||||
|
@ -263,6 +278,11 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal compared with variable 'c'. Did you intend to use strcmp() instead?\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal compared with variable 'c'. Did you intend to use strcmp() instead?\n", errout.str());
|
||||||
|
|
||||||
|
check("bool foo(wchar_t* c) {\n"
|
||||||
|
" return c == L\"x\";\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal compared with variable 'c'. Did you intend to use wcscmp() instead?\n", errout.str());
|
||||||
|
|
||||||
check("bool foo(const char* c) {\n"
|
check("bool foo(const char* c) {\n"
|
||||||
" return \"x\" == c;\n"
|
" return \"x\" == c;\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -370,6 +390,11 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Char literal compared with pointer 'c'. Did you intend to dereference it?\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Char literal compared with pointer 'c'. Did you intend to dereference it?\n", errout.str());
|
||||||
|
|
||||||
|
check("bool foo(wchar_t* c) {\n"
|
||||||
|
" return c == L'x';\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Char literal compared with pointer 'c'. Did you intend to dereference it?\n", errout.str());
|
||||||
|
|
||||||
check("bool foo(char* c) {\n"
|
check("bool foo(char* c) {\n"
|
||||||
" return '\\0' != c;\n"
|
" return '\\0' != c;\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -419,13 +444,22 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void snprintf1() {
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" char buf[100];\n"
|
||||||
|
" snprintf(buf,100,\"%s\",buf);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Undefined behavior: Variable 'buf' is used as parameter and destination in snprintf().\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void sprintf1() {
|
void sprintf1() {
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" char buf[100];\n"
|
" char buf[100];\n"
|
||||||
" sprintf(buf,\"%s\",buf);\n"
|
" sprintf(buf,\"%s\",buf);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Undefined behavior: Variable 'buf' is used as parameter and destination in s[n]printf().\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (error) Undefined behavior: Variable 'buf' is used as parameter and destination in sprintf().\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprintf2() {
|
void sprintf2() {
|
||||||
|
@ -462,6 +496,15 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wsprintf1() {
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" wchar_t buf[100];\n"
|
||||||
|
" swprintf(buf,10, \"%s\",buf);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Undefined behavior: Variable 'buf' is used as parameter and destination in swprintf().\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void strPlusChar1() {
|
void strPlusChar1() {
|
||||||
// Strange looking pointer arithmetic..
|
// Strange looking pointer arithmetic..
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
|
@ -500,30 +543,49 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void strPlusChar4() {
|
||||||
|
// Strange looking pointer arithmetic, wide char..
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" const wchar_t *p = L\"/usr\" + L'/';\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Unusual pointer arithmetic. A value of type 'wchar_t' is added to a string literal.\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(wchar_t c)\n"
|
||||||
|
"{\n"
|
||||||
|
" const wchar_t *p = L\"/usr\" + c;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Unusual pointer arithmetic. A value of type 'wchar_t' is added to a string literal.\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void incorrectStringCompare() {
|
void incorrectStringCompare() {
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" return test.substr( 0 , 4 ) == \"Hello\" ? : 0 : 1 ;\n"
|
" return test.substr( 0 , 4 ) == \"Hello\" ? 0 : 1 ;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
||||||
|
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" return test.substr( 0 , 5 ) == \"Hello\" ? : 0 : 1 ;\n"
|
" return test.substr( 0 , 4 ) == L\"Hello\" ? 0 : 1 ;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
||||||
|
|
||||||
|
check("int f() {\n"
|
||||||
|
" return test.substr( 0 , 5 ) == \"Hello\" ? 0 : 1 ;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" return \"Hello\" == test.substr( 0 , 4 ) ? : 0 : 1 ;\n"
|
" return \"Hello\" == test.substr( 0 , 4 ) ? 0 : 1 ;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
||||||
|
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" return \"Hello\" == foo.bar<int>().z[1].substr(i+j*4, 4) ? : 0 : 1 ;\n"
|
" return \"Hello\" == foo.bar<int>().z[1].substr(i+j*4, 4) ? 0 : 1 ;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) String literal \"Hello\" doesn't match length argument for substr().\n", errout.str());
|
||||||
|
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" return \"Hello\" == test.substr( 0 , 5 ) ? : 0 : 1 ;\n"
|
" return \"Hello\" == test.substr( 0 , 5 ) ? 0 : 1 ;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
@ -547,6 +609,11 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of string literal \"Hello\" to bool always evaluates to true.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of string literal \"Hello\" to bool always evaluates to true.\n", errout.str());
|
||||||
|
|
||||||
|
check("int f() {\n"
|
||||||
|
" return \"Hello\" ? 1 : 2;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of string literal \"Hello\" to bool always evaluates to true.\n", errout.str());
|
||||||
|
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
" assert (test || \"Hello\");\n"
|
" assert (test || \"Hello\");\n"
|
||||||
"}");
|
"}");
|
||||||
|
@ -582,22 +649,26 @@ private:
|
||||||
" if('a'){}\n"
|
" if('a'){}\n"
|
||||||
" if(L'b'){}\n"
|
" if(L'b'){}\n"
|
||||||
" if(1 && 'c'){}\n"
|
" if(1 && 'c'){}\n"
|
||||||
" int x = 'd' ? 1 : 2;\n" // <- TODO
|
" int x = 'd' ? 1 : 2;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal 'a' to bool always evaluates to true.\n"
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal 'a' to bool always evaluates to true.\n"
|
||||||
"[test.cpp:3]: (warning) Conversion of char literal 'b' to bool always evaluates to true.\n"
|
"[test.cpp:3]: (warning) Conversion of char literal 'b' to bool always evaluates to true.\n"
|
||||||
"[test.cpp:4]: (warning) Conversion of char literal 'c' to bool always evaluates to true.\n"
|
"[test.cpp:4]: (warning) Conversion of char literal 'c' to bool always evaluates to true.\n"
|
||||||
|
"[test.cpp:5]: (warning) Conversion of char literal 'd' to bool always evaluates to true.\n"
|
||||||
, errout.str());
|
, errout.str());
|
||||||
|
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" if('\\0'){}\n"
|
" if('\\0'){}\n"
|
||||||
|
" if(L'\\0'){}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" if('\\0' || cond){}\n"
|
" if('\\0' || cond){}\n"
|
||||||
|
" if(L'\\0' || cond){}\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n"
|
||||||
|
"[test.cpp:3]: (warning) Conversion of char literal '\\0' to bool always evaluates to false.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void deadStrcmp() {
|
void deadStrcmp() {
|
||||||
|
@ -606,6 +677,11 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:2]: (warning) The expression 'strcmp(str,\"def\") != 0' is suspicious. It overlaps 'strcmp(str,\"abc\") == 0'.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:2]: (warning) The expression 'strcmp(str,\"def\") != 0' is suspicious. It overlaps 'strcmp(str,\"abc\") == 0'.\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(const wchar_t *str) {\n"
|
||||||
|
" if (wcscmp(str, L\"abc\") == 0 || wcscmp(str, L\"def\")) {}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (warning) The expression 'wcscmp(str,L\"def\") != 0' is suspicious. It overlaps 'wcscmp(str,L\"abc\") == 0'.\n", errout.str());
|
||||||
|
|
||||||
check("struct X {\n"
|
check("struct X {\n"
|
||||||
" char *str;\n"
|
" char *str;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
|
|
Loading…
Reference in New Issue