Fixed #1748 (Undefined Behavior: Modification of string literal)

This commit is contained in:
Daniel Marjamäki 2015-05-03 10:44:40 +02:00
parent 70a1e11ada
commit 9d31afb663
3 changed files with 51 additions and 0 deletions

View File

@ -29,6 +29,30 @@ namespace {
} }
//---------------------------------------------------------------------------
// Writing string literal is UB
//---------------------------------------------------------------------------
void CheckString::stringLiteralWrite()
{
for (const Token* tok = _tokenizer->tokens(); tok; tok = tok->next()) {
if (!tok->variable())
continue;
const Token *str = tok->getValueTokenMinStrSize();
if (!str)
continue;
if (Token::Match(tok, "%var% [") && Token::Match(tok->linkAt(1), "] ="))
stringLiteralWriteError(tok);
else if (Token::Match(tok->previous(), "* %var% ="))
stringLiteralWriteError(tok);
}
}
void CheckString::stringLiteralWriteError(const Token *tok)
{
reportError(tok, Severity::error, "stringLiteralWrite",
"Modifying string literal directly or indirectly is UB");
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check for string comparison involving two static strings. // Check for string comparison involving two static strings.
// if(strcmp("00FF00","00FF00")==0) // <- statement is always true // if(strcmp("00FF00","00FF00")==0) // <- statement is always true

View File

@ -59,8 +59,12 @@ public:
checkString.checkIncorrectStringCompare(); checkString.checkIncorrectStringCompare();
checkString.checkAlwaysTrueOrFalseStringCompare(); checkString.checkAlwaysTrueOrFalseStringCompare();
checkString.sprintfOverlappingData(); checkString.sprintfOverlappingData();
checkString.stringLiteralWrite();
} }
/** @brief undefined behaviour, writing string literal */
void stringLiteralWrite();
/** @brief str plus char (unusual pointer arithmetic) */ /** @brief str plus char (unusual pointer arithmetic) */
void strPlusChar(); void strPlusChar();
@ -77,6 +81,7 @@ public:
void sprintfOverlappingData(); void sprintfOverlappingData();
private: private:
void stringLiteralWriteError(const Token *tok);
void sprintfOverlappingDataError(const Token *tok, const std::string &varname); void sprintfOverlappingDataError(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);

View File

@ -32,6 +32,8 @@ public:
private: private:
void run() { void run() {
TEST_CASE(stringLiteralWrite);
TEST_CASE(alwaysTrueFalseStringCompare); TEST_CASE(alwaysTrueFalseStringCompare);
TEST_CASE(suspiciousStringCompare); TEST_CASE(suspiciousStringCompare);
TEST_CASE(suspiciousStringCompare_char); TEST_CASE(suspiciousStringCompare_char);
@ -95,6 +97,26 @@ private:
checkString.checkAlwaysTrueOrFalseStringCompare(); checkString.checkAlwaysTrueOrFalseStringCompare();
} }
void stringLiteralWrite() {
check("void f() {\n"
" char *abc = \"abc\";\n"
" abc[0] = 'a';\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Modifying string literal directly or indirectly is UB\n", errout.str());
check("void f() {\n"
" char *abc = \"abc\";\n"
" *abc = 'a';\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Modifying string literal directly or indirectly is UB\n", errout.str());
check("void f() {\n"
" char *abc = \"abc\";\n"
" if (*abc == 'a'){}\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void alwaysTrueFalseStringCompare() { void alwaysTrueFalseStringCompare() {
check("void f() {\n" check("void f() {\n"
" if (strcmp(\"A\",\"A\")){}\n" " if (strcmp(\"A\",\"A\")){}\n"