From ea51c3e0982da298d64cd77056ab0e5cd9224730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 23 Dec 2009 19:51:32 +0100 Subject: [PATCH] Refactoring the uninitialized variable / null pointer checks so they use a common function to inspect function calls --- lib/checkother.cpp | 86 ++++++++++++++++++++++++++++++++++++++++------ test/testother.cpp | 7 ++++ 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 2926c4356..1bebcc605 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1118,6 +1118,68 @@ void CheckOther::nullPointer() } +/** + * \brief parse a function call and extract information about variable usage + * \param tok first token + * \param var variables that the function read / write. + * \param value 0 => invalid with null pointers as parameter. + * 1-.. => invalid with uninitialized data. + */ +static void parseFunctionCall(const Token &tok, std::list &var, unsigned char value) +{ + // standard functions that dereference first parameter.. + // both uninitialized data and null pointers are invalid. + static std::set functionNames1; + if (functionNames1.empty()) + { + functionNames1.insert("memchr"); + functionNames1.insert("memcmp"); + functionNames1.insert("strcat"); + functionNames1.insert("strncat"); + functionNames1.insert("strchr"); + functionNames1.insert("strrchr"); + functionNames1.insert("strcmp"); + functionNames1.insert("strncmp"); + functionNames1.insert("strdup"); + functionNames1.insert("strlen"); + functionNames1.insert("strstr"); + } + + // standard functions that dereference second parameter.. + // both uninitialized data and null pointers are invalid. + static std::set functionNames2; + if (functionNames2.empty()) + { + functionNames2.insert("memcmp"); + functionNames2.insert("memcpy"); + functionNames2.insert("memmove"); + functionNames2.insert("strcat"); + functionNames2.insert("strncat"); + functionNames2.insert("strcmp"); + functionNames2.insert("strncmp"); + functionNames2.insert("strcpy"); + functionNames2.insert("strncpy"); + functionNames2.insert("strstr"); + } + + // 1st parameter.. + if (Token::Match(&tok, "%var% ( %var% ,|)") && tok.tokAt(2)->varId() > 0) + { + if (functionNames1.find(tok.str()) != functionNames1.end()) + var.push_back(tok.tokAt(2)); + else if (value == 0 && Token::Match(&tok, "memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf")) + var.push_back(tok.tokAt(2)); + else if (Token::Match(&tok, "free|kfree|fclose|fflush")) + var.push_back(tok.tokAt(2)); + } + + // 2nd parameter.. + if (Token::Match(&tok, "%var% ( %any% , %var% ,|)") && tok.tokAt(4)->varId() > 0) + { + if (functionNames2.find(tok.str()) != functionNames2.end()) + var.push_back(tok.tokAt(4)); + } +} class CheckNullpointer : public ExecutionPath @@ -1190,6 +1252,15 @@ private: return vartok->next(); } + if (Token::Match(tok.previous(), "[;{}] %var% (")) + { + // parse usage.. + std::list var; + parseFunctionCall(tok, var, 0); + for (std::list::const_iterator it = var.begin(); it != var.end(); ++it) + dereference(foundError, checks, *it); + } + if (tok.varId() != 0) { if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;")) @@ -1397,17 +1468,12 @@ private: if (Token::Match(&tok, "%var% (")) { - // reading 1st parameter.. - if (Token::Match(&tok, "strcat|strncat|strchr|strrchr|strstr|strlen|strdup ( %var%")) + // parse usage.. { - use_array(foundError, checks, tok.tokAt(2)); - } - - // reading 2nd parameter.. - if (Token::Match(&tok, "strcpy|strstr ( %any% , %var% ) ") || - Token::Match(&tok, "strncpy ( %any% , %var% ,")) - { - use_array(foundError, checks, tok.tokAt(4)); + std::list var; + parseFunctionCall(tok, var, 1); + for (std::list::const_iterator it = var.begin(); it != var.end(); ++it) + use_array(foundError, checks, *it); } // strncpy doesn't 0-terminate first parameter diff --git a/test/testother.cpp b/test/testother.cpp index 9a81b9a7e..554ecfe6d 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1211,6 +1211,13 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + checkUninitVar("void f()\n" + "{\n" + " FILE *f;\n" + " fflush(f);\n" + "}\n"); + ASSERT_EQUALS("error", errout.str()); + // arrays.. checkUninitVar("void f()\n" "{\n"