diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index fd9168f9a..ec5e46158 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -660,25 +660,33 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std:: if (!fi) continue; for (const CTU::FileInfo::UnsafeUsage &unsafeUsage : fi->unsafeUsage) { - const std::list &locationList = - ctu->getErrorPath(CTU::FileInfo::InvalidValueType::null, - unsafeUsage, - callsMap, - "Dereferencing argument ARG that is null", - nullptr); - if (locationList.empty()) - continue; + for (int warning = 0; warning <= 1; warning++) { + if (warning == 1 && !settings.isEnabled(Settings::WARNING)) + break; - const ErrorLogger::ErrorMessage errmsg(locationList, - emptyString, - Severity::error, - "Null pointer dereference: " + unsafeUsage.myArgumentName, - "ctunullpointer", - CWE476, false); - errorLogger.reportErr(errmsg); + const std::list &locationList = + ctu->getErrorPath(CTU::FileInfo::InvalidValueType::null, + unsafeUsage, + callsMap, + "Dereferencing argument ARG that is null", + nullptr, + warning); + if (locationList.empty()) + continue; - foundErrors = true; - break; + const ErrorLogger::ErrorMessage errmsg(locationList, + emptyString, + warning ? Severity::warning : Severity::error, + "Null pointer dereference: " + unsafeUsage.myArgumentName, + "ctunullpointer", + CWE476, false); + errorLogger.reportErr(errmsg); + + foundErrors = true; + break; + } + if (foundErrors) + break; } } diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 846c4612c..1a6e102e6 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1339,7 +1339,8 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo *ctu, const std::li unsafeUsage, callsMap, "Using argument ARG", - &functionCall); + &functionCall, + false); if (locationList.empty()) continue; diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 8eaae5b3e..c8e10ea2f 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -30,8 +30,10 @@ static const char ATTR_CALL_ARGNR[] = "call-argnr"; static const char ATTR_CALL_ARGEXPR[] = "call-argexpr"; static const char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype"; static const char ATTR_CALL_ARGVALUE[] = "call-argvalue"; -static const char ATTR_LOC_FILENAME[] = "loc-filename"; -static const char ATTR_LOC_LINENR[] = "loc-linenr"; +static const char ATTR_WARNING[] = "warning"; +static const char ATTR_LOC_FILENAME[] = "filename"; +static const char ATTR_LOC_LINENR[] = "linenr"; +static const char ATTR_INFO[] = "info"; static const char ATTR_MY_ID[] = "my-id"; static const char ATTR_MY_ARGNR[] = "my-argnr"; static const char ATTR_MY_ARGNAME[] = "my-argname"; @@ -83,8 +85,20 @@ std::string CTU::FileInfo::FunctionCall::toXmlString() const << toBaseXmlString() << " " << ATTR_CALL_ARGEXPR << "=\"" << callArgumentExpression << "\"" << " " << ATTR_CALL_ARGVALUETYPE << "=\"" << callValueType << "\"" - << " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue << "\"" - << "/>"; + << " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue << "\""; + if (warning) + out << " " << ATTR_WARNING << "=\"true\""; + if (callValuePath.empty()) + out << "/>"; + else { + out << ">\n"; + for (const ErrorLogger::ErrorMessage::FileLocation &loc : callValuePath) + out << " \n"; + out << ""; + } return out.str(); } @@ -170,6 +184,16 @@ bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *e) callArgumentExpression = readAttrString(e, ATTR_CALL_ARGEXPR, &error); callValueType = (ValueFlow::Value::ValueType)readAttrInt(e, ATTR_CALL_ARGVALUETYPE, &error); callArgValue = readAttrInt(e, ATTR_CALL_ARGVALUE, &error); + const char *w = e->Attribute(ATTR_WARNING); + warning = w && std::strcmp(w, "true") == 0; + for (const tinyxml2::XMLElement *e2 = e->FirstChildElement(); !error && e2; e2 = e2->NextSiblingElement()) { + if (std::strcmp(e2->Name(), "path") != 0) + continue; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.setfile(readAttrString(e2, ATTR_LOC_FILENAME, &error)); + loc.line = readAttrInt(e2, ATTR_LOC_LINENR, &error); + loc.setinfo(readAttrString(e2, ATTR_INFO, &error)); + } return !error; } @@ -280,7 +304,9 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) const Token *argtok = args[argnr]; if (!argtok) continue; - if (argtok->hasKnownIntValue()) { + for (const ValueFlow::Value &value : argtok->values()) { + if (!value.isIntValue() || value.intvalue != 0 || value.isInconclusive()) + continue; struct FileInfo::FunctionCall functionCall; functionCall.callValueType = ValueFlow::Value::INT; functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); @@ -289,9 +315,16 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) functionCall.location.linenr = tok->linenr(); functionCall.callArgNr = argnr + 1; functionCall.callArgumentExpression = argtok->expressionString(); - functionCall.callArgValue = argtok->values().front().intvalue; + functionCall.callArgValue = value.intvalue; + functionCall.warning = (value.condition != nullptr); + for (const ErrorPathItem &i : value.errorPath) { + ErrorLogger::ErrorMessage::FileLocation loc; + loc.setfile(tokenizer->list.file(i.first)); + loc.line = i.first->linenr(); + loc.setinfo(i.second); + functionCall.callValuePath.push_back(loc); + } fileInfo->functionCalls.push_back(functionCall); - continue; } // pointer to uninitialized data.. if (!argtok->isUnaryOp("&")) @@ -312,6 +345,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) functionCall.callArgNr = argnr + 1; functionCall.callArgValue = 0; functionCall.callArgumentExpression = argtok->expressionString(); + functionCall.warning = false; fileInfo->functionCalls.push_back(functionCall); continue; } @@ -385,7 +419,8 @@ static bool findPath(const std::string &callId, CTU::FileInfo::InvalidValueType invalidValue, const std::map> &callsMap, const CTU::FileInfo::CallBase *path[10], - int index) + int index, + bool warning) { if (index >= 10) return false; @@ -400,6 +435,8 @@ static bool findPath(const std::string &callId, const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast(c); if (functionCall) { + if (!warning && functionCall->warning) + continue; switch (invalidValue) { case CTU::FileInfo::InvalidValueType::null: if (functionCall->callValueType != ValueFlow::Value::INT || functionCall->callArgValue != 0) @@ -418,7 +455,7 @@ static bool findPath(const std::string &callId, if (!nestedCall) continue; - if (findPath(nestedCall->myId, nestedCall->myArgNr, invalidValue, callsMap, path, index + 1)) { + if (findPath(nestedCall->myId, nestedCall->myArgNr, invalidValue, callsMap, path, index + 1, warning)) { path[index] = nestedCall; return true; } @@ -431,13 +468,14 @@ std::list CTU::FileInfo::getErrorPath(I const CTU::FileInfo::UnsafeUsage &unsafeUsage, const std::map> &callsMap, const char info[], - const FunctionCall * * const functionCallPtr) const + const FunctionCall * * const functionCallPtr, + bool warning) const { std::list locationList; const CTU::FileInfo::CallBase *path[10] = {0}; - if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, invalidValue, callsMap, path, 0)) + if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, invalidValue, callsMap, path, 0, warning)) return locationList; const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized"; @@ -446,8 +484,14 @@ std::list CTU::FileInfo::getErrorPath(I if (!path[index]) continue; - if (functionCallPtr && !*functionCallPtr) - *functionCallPtr = dynamic_cast(path[index]); + const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast(path[index]); + + if (functionCall) { + if (functionCallPtr) + *functionCallPtr = functionCall; + for (const ErrorLogger::ErrorMessage::FileLocation &loc : functionCall->callValuePath) + locationList.push_back(loc); + } ErrorLogger::ErrorMessage::FileLocation fileLoc; fileLoc.setfile(path[index]->location.fileName); diff --git a/lib/ctu.h b/lib/ctu.h index 7f493dd4b..70b94539a 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -75,8 +75,10 @@ namespace CTU { class FunctionCall : public CallBase { public: std::string callArgumentExpression; - long long callArgValue; + MathLib::bigint callArgValue; ValueFlow::Value::ValueType callValueType; + std::vector callValuePath; + bool warning; std::string toXmlString() const; bool loadFromXml(const tinyxml2::XMLElement *xmlElement); @@ -111,7 +113,8 @@ namespace CTU { const UnsafeUsage &unsafeUsage, const std::map> &callsMap, const char info[], - const FunctionCall * * const functionCallPtr) const; + const FunctionCall * * const functionCallPtr, + bool warning) const; }; CPPCHECKLIB std::string toString(const std::list &unsafeUsage); diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 627edd936..b415ce2a1 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -2705,6 +2705,7 @@ private: " f(p);\n" "}"); ASSERT_EQUALS("test.cpp:2:error:Null pointer dereference: fp\n" + "test.cpp:5:note:Assignment 'p=0', assigned value is 0\n" "test.cpp:6:note:Calling function f, 1st argument is null\n" "test.cpp:2:note:Dereferencing argument fp that is null\n", errout.str());