From 4f30468c80e954c8f91e95052d777caf31a01e58 Mon Sep 17 00:00:00 2001 From: Monika Lukow Date: Sun, 31 Jan 2010 11:42:02 +0100 Subject: [PATCH] Fixed #1094 (Improve check: unusual pointer arithmetic: 'ch+str') --- lib/checkother.cpp | 85 +++++++++++++++++++++++++++++++++++++++++----- test/testother.cpp | 54 +++++++++++++++++++++++++---- 2 files changed, 124 insertions(+), 15 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 0ff5f72f2..91cb13d67 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -811,24 +811,70 @@ void CheckOther::checkIncompleteStatement() //--------------------------------------------------------------------------- // str plus char +// +// What is checked: +// string = string + "xxx" + 'x'; OK +// string = const char * + %any%; ERR +// string = 'x' + %any%; ERR +// string = char + %any%; ERR +// const char * = "xxx" + %number%; OK +// +// where: +// string - variable of type string +// const char * - variable of type const char * +// 'x' - a character literal +// "xxx" - a string literal +// %any% - anything (variable or literal) +// %number% - a number (literal or variable) //--------------------------------------------------------------------------- void CheckOther::strPlusChar() { - bool charVars[10000] = {0}; + char strVars[10000] = {0}; // 1 - string, 2 - const char *, 3 - number (char,int,short), 0 - other + char assignToConstChar = 0; // 1 - assigning to const char *, 2 - 'const char*'-part assigned for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - // Declaring char variable.. - if (Token::Match(tok, "char %var% [;=]")) + if (assignToConstChar) + { + if (Token::Match(tok, "%var%")) + { + unsigned int varid = tok->varId(); + + if (strVars[varid] == 2) + { + assignToConstChar = 2; + } + else if (!(tok->isNumber() || (strVars[varid] == 3))) + { + strPlusChar(tok); + } + } + else if (Token::Match(tok, "%str%")) + { + assignToConstChar = 2; + } + else if (Token::Match(tok, ";")) + { + // 'const char *'-part was not found + if (assignToConstChar != 2) + { + strPlusChar(tok); + } + assignToConstChar = 0; + } + else if (!(Token::Match(tok, "[+=]") || tok->isNumber())) + { + strPlusChar(tok); + } + } + else if (Token::Match(tok, "string %var% [;=]")) { unsigned int varid = tok->next()->varId(); if (varid > 0 && varid < 10000) - charVars[varid] = true; + strVars[varid] = 1; } - - // - else if (Token::Match(tok, "[=(] %str% + %any%")) + else if (Token::Match(tok, "const char * %var% [;=]")) { // char constant.. const char *s = tok->strAt(3); @@ -837,8 +883,29 @@ void CheckOther::strPlusChar() // char variable.. unsigned int varid = tok->tokAt(3)->varId(); - if (varid > 0 && varid < 10000 && charVars[varid]) - strPlusChar(tok->next()); + if (varid > 0 && varid < 10000) + strVars[varid] = 2; + } + else if (Token::Match(tok, "char|int|short %var% [;=]")) + { + unsigned int varid = tok->next()->varId(); + if (varid > 0 && varid < 10000) + strVars[varid] = 3; + } + else if (Token::Match(tok, "%var% = %any% + %any%") && + (strVars[tok->varId()] == 1)) + { + // string = + unsigned int varidAny = tok->tokAt(2)->varId(); + // first %any% has to be a variable of type string + if (!strVars[varidAny]) + strPlusChar(tok->tokAt(3)); + } + else if (Token::Match(tok, "%var% = %any%") && + (strVars[tok->varId()] == 2)) + { + // const char * = + assignToConstChar = 1; } } } diff --git a/test/testother.cpp b/test/testother.cpp index 918ae1d81..731f5a0a7 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -49,9 +49,10 @@ private: TEST_CASE(sprintf3); TEST_CASE(sprintf4); // struct member - TEST_CASE(strPlusChar1); // "/usr" + '/' - TEST_CASE(strPlusChar2); // "/usr" + ch - TEST_CASE(strPlusChar3); // ok: path + "/sub" + '/' + TEST_CASE(strPlusChar1); // "/usr" + '/' + TEST_CASE(strPlusChar2); // "/usr" + ch + TEST_CASE(strPlusChar3); // ok : path + "/sub" + '/'; err: '/' + path + "/sub" + TEST_CASE(strPlusChar4); // ok : + TEST_CASE(varScope1); TEST_CASE(varScope2); @@ -423,6 +424,12 @@ private: " const char *p = \"/usr\" + '/';\n" "}\n"); ASSERT_EQUALS("[test.cpp:3]: (error) Unusual pointer arithmetic\n", errout.str()); + + strPlusChar("void foo()\n" + "{\n" + " const char *p = '/' + \"/usr\";\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Unusual pointer arithmetic\n", errout.str()); } void strPlusChar2() @@ -430,10 +437,23 @@ private: // Strange looking pointer arithmetic.. strPlusChar("void foo()\n" "{\n" - " char ch = '/';\n" - " const char *p = \"/usr\" + ch;\n" + " int x = 1;\n" + " const char *p = \"/usr\" + x;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:4]: (error) Unusual pointer arithmetic\n", errout.str()); + ASSERT_EQUALS("", errout.str()); + + strPlusChar("void foo()\n" + "{\n" + " const char *p = \"/usr\" + 1;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + strPlusChar("void foo()\n" + "{\n" + " char ch = '/';\n" + " const char *p = ch + \"/usr\";\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void strPlusChar3() @@ -445,9 +465,31 @@ private: " std::string path = temp + '/' + \"sub\" + '/';\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + strPlusChar("void foo()\n" + "{\n" + " std::string path = '/' + \"sub\" + '/';\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Unusual pointer arithmetic\n", errout.str()); } + void strPlusChar4() + { + // Strange looking pointer arithmetic.. + strPlusChar("void foo()\n" + "{\n" + " const char *p = \"abcd\" + 1;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + strPlusChar("void foo()\n" + "{\n" + " char ch = 1;\n" + " const char *p = \"abcd\";\n" + " const char *s = ch + p;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } void varScope(const char code[]) {