CTU: more warnings

This commit is contained in:
Daniel Marjamäki 2018-12-30 18:31:37 +01:00
parent c8901e9bab
commit 91a580cbd7
5 changed files with 90 additions and 33 deletions

View File

@ -660,18 +660,23 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std::
if (!fi) if (!fi)
continue; continue;
for (const CTU::FileInfo::UnsafeUsage &unsafeUsage : fi->unsafeUsage) { for (const CTU::FileInfo::UnsafeUsage &unsafeUsage : fi->unsafeUsage) {
for (int warning = 0; warning <= 1; warning++) {
if (warning == 1 && !settings.isEnabled(Settings::WARNING))
break;
const std::list<ErrorLogger::ErrorMessage::FileLocation> &locationList = const std::list<ErrorLogger::ErrorMessage::FileLocation> &locationList =
ctu->getErrorPath(CTU::FileInfo::InvalidValueType::null, ctu->getErrorPath(CTU::FileInfo::InvalidValueType::null,
unsafeUsage, unsafeUsage,
callsMap, callsMap,
"Dereferencing argument ARG that is null", "Dereferencing argument ARG that is null",
nullptr); nullptr,
warning);
if (locationList.empty()) if (locationList.empty())
continue; continue;
const ErrorLogger::ErrorMessage errmsg(locationList, const ErrorLogger::ErrorMessage errmsg(locationList,
emptyString, emptyString,
Severity::error, warning ? Severity::warning : Severity::error,
"Null pointer dereference: " + unsafeUsage.myArgumentName, "Null pointer dereference: " + unsafeUsage.myArgumentName,
"ctunullpointer", "ctunullpointer",
CWE476, false); CWE476, false);
@ -680,6 +685,9 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std::
foundErrors = true; foundErrors = true;
break; break;
} }
if (foundErrors)
break;
}
} }
return foundErrors; return foundErrors;

View File

@ -1339,7 +1339,8 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo *ctu, const std::li
unsafeUsage, unsafeUsage,
callsMap, callsMap,
"Using argument ARG", "Using argument ARG",
&functionCall); &functionCall,
false);
if (locationList.empty()) if (locationList.empty())
continue; continue;

View File

@ -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_ARGEXPR[] = "call-argexpr";
static const char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype"; static const char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype";
static const char ATTR_CALL_ARGVALUE[] = "call-argvalue"; static const char ATTR_CALL_ARGVALUE[] = "call-argvalue";
static const char ATTR_LOC_FILENAME[] = "loc-filename"; static const char ATTR_WARNING[] = "warning";
static const char ATTR_LOC_LINENR[] = "loc-linenr"; 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_ID[] = "my-id";
static const char ATTR_MY_ARGNR[] = "my-argnr"; static const char ATTR_MY_ARGNR[] = "my-argnr";
static const char ATTR_MY_ARGNAME[] = "my-argname"; static const char ATTR_MY_ARGNAME[] = "my-argname";
@ -83,8 +85,20 @@ std::string CTU::FileInfo::FunctionCall::toXmlString() const
<< toBaseXmlString() << toBaseXmlString()
<< " " << ATTR_CALL_ARGEXPR << "=\"" << callArgumentExpression << "\"" << " " << ATTR_CALL_ARGEXPR << "=\"" << callArgumentExpression << "\""
<< " " << ATTR_CALL_ARGVALUETYPE << "=\"" << callValueType << "\"" << " " << 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 << " <path"
<< " " << ATTR_LOC_FILENAME << "=\"" << loc.getfile() << "\""
<< " " << ATTR_LOC_LINENR << "=\"" << loc.line << "\""
<< " " << ATTR_INFO << "=\"" << loc.getinfo() << "\"/>\n";
out << "</function-call>";
}
return out.str(); return out.str();
} }
@ -170,6 +184,16 @@ bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *e)
callArgumentExpression = readAttrString(e, ATTR_CALL_ARGEXPR, &error); callArgumentExpression = readAttrString(e, ATTR_CALL_ARGEXPR, &error);
callValueType = (ValueFlow::Value::ValueType)readAttrInt(e, ATTR_CALL_ARGVALUETYPE, &error); callValueType = (ValueFlow::Value::ValueType)readAttrInt(e, ATTR_CALL_ARGVALUETYPE, &error);
callArgValue = readAttrInt(e, ATTR_CALL_ARGVALUE, &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; return !error;
} }
@ -280,7 +304,9 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
const Token *argtok = args[argnr]; const Token *argtok = args[argnr];
if (!argtok) if (!argtok)
continue; continue;
if (argtok->hasKnownIntValue()) { for (const ValueFlow::Value &value : argtok->values()) {
if (!value.isIntValue() || value.intvalue != 0 || value.isInconclusive())
continue;
struct FileInfo::FunctionCall functionCall; struct FileInfo::FunctionCall functionCall;
functionCall.callValueType = ValueFlow::Value::INT; functionCall.callValueType = ValueFlow::Value::INT;
functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function());
@ -289,9 +315,16 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
functionCall.location.linenr = tok->linenr(); functionCall.location.linenr = tok->linenr();
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
functionCall.callArgumentExpression = argtok->expressionString(); 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); fileInfo->functionCalls.push_back(functionCall);
continue;
} }
// pointer to uninitialized data.. // pointer to uninitialized data..
if (!argtok->isUnaryOp("&")) if (!argtok->isUnaryOp("&"))
@ -312,6 +345,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
functionCall.callArgNr = argnr + 1; functionCall.callArgNr = argnr + 1;
functionCall.callArgValue = 0; functionCall.callArgValue = 0;
functionCall.callArgumentExpression = argtok->expressionString(); functionCall.callArgumentExpression = argtok->expressionString();
functionCall.warning = false;
fileInfo->functionCalls.push_back(functionCall); fileInfo->functionCalls.push_back(functionCall);
continue; continue;
} }
@ -385,7 +419,8 @@ static bool findPath(const std::string &callId,
CTU::FileInfo::InvalidValueType invalidValue, CTU::FileInfo::InvalidValueType invalidValue,
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap, const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
const CTU::FileInfo::CallBase *path[10], const CTU::FileInfo::CallBase *path[10],
int index) int index,
bool warning)
{ {
if (index >= 10) if (index >= 10)
return false; return false;
@ -400,6 +435,8 @@ static bool findPath(const std::string &callId,
const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c); const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
if (functionCall) { if (functionCall) {
if (!warning && functionCall->warning)
continue;
switch (invalidValue) { switch (invalidValue) {
case CTU::FileInfo::InvalidValueType::null: case CTU::FileInfo::InvalidValueType::null:
if (functionCall->callValueType != ValueFlow::Value::INT || functionCall->callArgValue != 0) if (functionCall->callValueType != ValueFlow::Value::INT || functionCall->callArgValue != 0)
@ -418,7 +455,7 @@ static bool findPath(const std::string &callId,
if (!nestedCall) if (!nestedCall)
continue; 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; path[index] = nestedCall;
return true; return true;
} }
@ -431,13 +468,14 @@ std::list<ErrorLogger::ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(I
const CTU::FileInfo::UnsafeUsage &unsafeUsage, const CTU::FileInfo::UnsafeUsage &unsafeUsage,
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap, const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
const char info[], const char info[],
const FunctionCall * * const functionCallPtr) const const FunctionCall * * const functionCallPtr,
bool warning) const
{ {
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList; std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
const CTU::FileInfo::CallBase *path[10] = {0}; 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; return locationList;
const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized"; const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
@ -446,8 +484,14 @@ std::list<ErrorLogger::ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(I
if (!path[index]) if (!path[index])
continue; continue;
if (functionCallPtr && !*functionCallPtr) const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
*functionCallPtr = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
if (functionCall) {
if (functionCallPtr)
*functionCallPtr = functionCall;
for (const ErrorLogger::ErrorMessage::FileLocation &loc : functionCall->callValuePath)
locationList.push_back(loc);
}
ErrorLogger::ErrorMessage::FileLocation fileLoc; ErrorLogger::ErrorMessage::FileLocation fileLoc;
fileLoc.setfile(path[index]->location.fileName); fileLoc.setfile(path[index]->location.fileName);

View File

@ -75,8 +75,10 @@ namespace CTU {
class FunctionCall : public CallBase { class FunctionCall : public CallBase {
public: public:
std::string callArgumentExpression; std::string callArgumentExpression;
long long callArgValue; MathLib::bigint callArgValue;
ValueFlow::Value::ValueType callValueType; ValueFlow::Value::ValueType callValueType;
std::vector<ErrorLogger::ErrorMessage::FileLocation> callValuePath;
bool warning;
std::string toXmlString() const; std::string toXmlString() const;
bool loadFromXml(const tinyxml2::XMLElement *xmlElement); bool loadFromXml(const tinyxml2::XMLElement *xmlElement);
@ -111,7 +113,8 @@ namespace CTU {
const UnsafeUsage &unsafeUsage, const UnsafeUsage &unsafeUsage,
const std::map<std::string, std::list<const CallBase *>> &callsMap, const std::map<std::string, std::list<const CallBase *>> &callsMap,
const char info[], const char info[],
const FunctionCall * * const functionCallPtr) const; const FunctionCall * * const functionCallPtr,
bool warning) const;
}; };
CPPCHECKLIB std::string toString(const std::list<FileInfo::UnsafeUsage> &unsafeUsage); CPPCHECKLIB std::string toString(const std::list<FileInfo::UnsafeUsage> &unsafeUsage);

View File

@ -2705,6 +2705,7 @@ private:
" f(p);\n" " f(p);\n"
"}"); "}");
ASSERT_EQUALS("test.cpp:2:error:Null pointer dereference: fp\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:6:note:Calling function f, 1st argument is null\n"
"test.cpp:2:note:Dereferencing argument fp that is null\n", errout.str()); "test.cpp:2:note:Dereferencing argument fp that is null\n", errout.str());