diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index d081afb12..cce0e0fc2 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1353,6 +1353,10 @@ void CheckClass::checkMemset() if (numIndirToVariableType == 1) type = var->typeScope(); + + if (!type && mSettings->library.detectContainerOrIterator(var->typeStartToken())) { + memsetError(tok, tok->str(), var->getTypeName(), {}, /*isContainer*/ true); + } } } @@ -1468,15 +1472,16 @@ void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.", CWE665, Certainty::normal); } -void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type) +void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer) { - reportError(tok, Severity::error, "memsetClass", - "$symbol:" + memfunc +"\n" - "$symbol:" + classname +"\n" - "Using '" + memfunc + "' on " + type + " that contains a " + classname + ".\n" - "Using '" + memfunc + "' on " + type + " that contains a " + classname + " is unsafe, because constructor, destructor " - "and copy operator calls are omitted. These are necessary for this non-POD type to ensure that a valid object " - "is created.", CWE762, Certainty::normal); + const std::string typeStr = isContainer ? std::string() : (type + " that contains a "); + const std::string msg = "$symbol:" + memfunc + "\n" + "$symbol:" + classname + "\n" + "Using '" + memfunc + "' on " + typeStr + classname + ".\n" + "Using '" + memfunc + "' on " + typeStr + classname + " is unsafe, because constructor, destructor " + "and copy operator calls are omitted. These are necessary for this non-POD type to ensure that a valid object " + "is created."; + reportError(tok, Severity::error, "memsetClass", msg, CWE762, Certainty::normal); } void CheckClass::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type) diff --git a/lib/checkclass.h b/lib/checkclass.h index cc7bcf9cd..19e2ca077 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -206,7 +206,7 @@ private: void missingMemberCopyError(const Token *tok, Function::Type functionType, const std::string& classname, const std::string& varname); void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive); void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname); - void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type); + void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer = false); void memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type); void memsetErrorFloat(const Token *tok, const std::string &type); void mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname); diff --git a/test/testclass.cpp b/test/testclass.cpp index 2aa74cedd..683739cc1 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -3109,6 +3109,16 @@ private: " memset(b, 0, sizeof(b));\n" "}"); ASSERT_EQUALS("", errout.str()); + + // #1655 + Settings s; + LOAD_LIB_2(s.library, "std.cfg"); + checkNoMemset("void f() {\n" + " char c[] = \"abc\";\n" + " std::string s;\n" + " memcpy(&s, c, strlen(c) + 1);\n" + "}\n", s); + ASSERT_EQUALS("[test.cpp:4]: (error) Using 'memcpy' on std::string.\n", errout.str()); } void memsetOnInvalid() { // Ticket #5425