From 378e0835853cd207a60dec8f6b018fee6aabd9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 30 Dec 2018 11:55:39 +0100 Subject: [PATCH] CTU: Refactoring the xml load/write. Renamed members. --- lib/checknullpointer.cpp | 2 +- lib/checkuninitvar.cpp | 2 +- lib/ctu.cpp | 267 ++++++++++++++++++++++----------------- lib/ctu.h | 65 ++++++---- 4 files changed, 193 insertions(+), 143 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index b0a6368c7..32fcdc9af 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -670,7 +670,7 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std:: const ErrorLogger::ErrorMessage errmsg(locationList, emptyString, Severity::error, - "Null pointer dereference: " + unsafeUsage.argumentName, + "Null pointer dereference: " + unsafeUsage.myArgumentName, "ctunullpointer", CWE476, false); errorLogger.reportErr(errmsg); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 81b17fb0c..c980ffd9a 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -1346,7 +1346,7 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo *ctu, const std::li const ErrorLogger::ErrorMessage errmsg(locationList, emptyString, Severity::error, - "Using argument " + unsafeUsage.argumentName + " that points at uninitialized variable " + functionCall->argumentExpression, + "Using argument " + unsafeUsage.myArgumentName + " that points at uninitialized variable " + functionCall->callArgumentExpression, "ctuuninitvar", CWE908, false); errorLogger.reportErr(errmsg); diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 73840cb7f..a847fbe0f 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -24,6 +24,19 @@ #include //--------------------------------------------------------------------------- +static const char ATTR_CALL_ID[] = "call-id"; +static const char ATTR_CALL_FUNCNAME[] = "call-funcname"; +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_MY_ID[] = "my-id"; +static const char ATTR_MY_ARGNR[] = "my-argnr"; +static const char ATTR_MY_ARGNAME[] = "my-argname"; + + std::string CTU::getFunctionId(const Tokenizer *tokenizer, const Function *function) { return tokenizer->list.file(function->tokenDef) + ':' + MathLib::toString(function->tokenDef->linenr()); @@ -41,43 +54,60 @@ std::string CTU::FileInfo::toString() const // Function calls.. for (const CTU::FileInfo::FunctionCall &functionCall : functionCalls) { - out << " \n"; + out << functionCall.toXmlString(); } // Nested calls.. for (const CTU::FileInfo::NestedCall &nestedCall : nestedCalls) { - out << " \n"; + out << nestedCall.toXmlString() << "\n"; } return out.str(); } +std::string CTU::FileInfo::CallBase::toBaseXmlString() const +{ + std::ostringstream out; + out << " " << ATTR_CALL_ID << "=\"" << callId << "\"" + << " " << ATTR_CALL_FUNCNAME << "=\"" << callFunctionName << "\"" + << " " << ATTR_CALL_ARGNR << "=\"" << callArgNr << "\"" + << " " << ATTR_LOC_FILENAME << "=\"" << location.fileName << "\"" + << " " << ATTR_LOC_LINENR << "=\"" << location.linenr << "\""; + return out.str(); +} + +std::string CTU::FileInfo::FunctionCall::toXmlString() const +{ + std::ostringstream out; + out << ""; + return out.str(); +} + +std::string CTU::FileInfo::NestedCall::toXmlString() const +{ + std::ostringstream out; + out << ""; + return out.str(); +} + std::string CTU::FileInfo::UnsafeUsage::toString() const { std::ostringstream out; out << " \n"; return out.str(); } @@ -90,65 +120,80 @@ std::string CTU::toString(const std::list &unsafeUsa return ret.str(); } -CTU::FileInfo::NestedCall::NestedCall(const Tokenizer *tokenizer, const Scope *scope, unsigned int argnr_, const Token *tok) - : - id(getFunctionId(tokenizer, scope->function)), - functionName(scope->className), - argnr(argnr_), - argnr2(0), - location(CTU::FileInfo::Location(tokenizer, tok)) +CTU::FileInfo::CallBase::CallBase(const Tokenizer *tokenizer, const Token *callToken) + : callId(getFunctionId(tokenizer, callToken->function())) + , callArgNr(0) + , callFunctionName(callToken->next()->astOperand1()->expressionString()) + , location(CTU::FileInfo::Location(tokenizer, callToken)) { } +CTU::FileInfo::NestedCall::NestedCall(const Tokenizer *tokenizer, const Function *myFunction, const Token *callToken) + : CallBase(tokenizer, callToken) + , myId(getFunctionId(tokenizer, myFunction)) + , myArgNr(0) +{ +} + +static std::string readAttrString(const tinyxml2::XMLElement *e, const char *attr, bool *error) +{ + const char *value = e->Attribute(attr); + if (!value && error) + *error = true; + return value ? value : ""; +} + +static long long readAttrInt(const tinyxml2::XMLElement *e, const char *attr, bool *error) +{ + const char *value = e->Attribute(attr); + if (!value && error) + *error = true; + return value ? std::atoi(value) : 0; +} + +bool CTU::FileInfo::CallBase::loadBaseFromXml(const tinyxml2::XMLElement *e) +{ + bool error = false; + callId = readAttrString(e, ATTR_CALL_ID, &error); + callFunctionName = readAttrString(e, ATTR_CALL_FUNCNAME, &error); + callArgNr = readAttrInt(e, ATTR_CALL_ARGNR, &error); + location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error); + location.linenr = readAttrInt(e, ATTR_LOC_LINENR, &error); + return !error; +} + +bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *e) +{ + if (!loadBaseFromXml(e)) + return false; + bool error=false; + callArgumentExpression = readAttrString(e, ATTR_CALL_ARGEXPR, &error); + callValueType = (ValueFlow::Value::ValueType)readAttrInt(e, ATTR_CALL_ARGVALUETYPE, &error); + callArgValue = readAttrInt(e, ATTR_CALL_ARGVALUE, &error); + return !error; +} + +bool CTU::FileInfo::NestedCall::loadFromXml(const tinyxml2::XMLElement *e) +{ + if (!loadBaseFromXml(e)) + return false; + bool error = false; + myId = readAttrString(e, ATTR_MY_ID, &error); + myArgNr = readAttrInt(e, ATTR_MY_ARGNR, &error); + return !error; +} + void CTU::FileInfo::loadFromXml(const tinyxml2::XMLElement *xmlElement) { for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) { - const char *id = e->Attribute("id"); - if (!id) - continue; - const char *functionName = e->Attribute("functionName"); - if (!functionName) - continue; - const char *argnr = e->Attribute("argnr"); - if (!argnr || !MathLib::isInt(argnr)) - continue; - const char *fileName = e->Attribute("fileName"); - if (!fileName) - continue; - const char *linenr = e->Attribute("linenr"); - if (!linenr || !MathLib::isInt(linenr)) - continue; - if (std::strcmp(e->Name(), "function-call") == 0) { FunctionCall functionCall; - functionCall.functionId = id; - functionCall.functionName = functionName; - functionCall.argnr = std::atoi(argnr); - const char *argExpr = e->Attribute("argExpr"); - if (!argExpr) - continue; - functionCall.argumentExpression = - functionCall.valueType = (ValueFlow::Value::ValueType)std::atoi(e->Attribute("valueType")); - functionCall.argvalue = MathLib::toLongNumber(e->Attribute("argvalue")); - functionCall.location.fileName = fileName; - functionCall.location.linenr = std::atoi(linenr); - functionCalls.push_back(functionCall); + if (functionCall.loadFromXml(e)) + functionCalls.push_back(functionCall); } else if (std::strcmp(e->Name(), "nested-call") == 0) { NestedCall nestedCall; - nestedCall.functionName = functionName; - nestedCall.id = id; - const char *id2 = e->Attribute("id2"); - if (!id2) - continue; - nestedCall.id2 = id2; - nestedCall.argnr = std::atoi(argnr); - const char *argnr2 = e->Attribute("argnr2"); - if (!argnr2 || !MathLib::isInt(argnr2)) - continue; - nestedCall.argnr2 = std::atoi(argnr2); - nestedCall.location.fileName = fileName; - nestedCall.location.linenr = std::atoi(linenr); - nestedCalls.push_back(nestedCall); + if (nestedCall.loadFromXml(e)) + nestedCalls.push_back(nestedCall); } } } @@ -157,7 +202,7 @@ std::map> CTU::FileInfo::getNe { std::map> ret; for (const CTU::FileInfo::NestedCall &nc : nestedCalls) - ret[nc.id].push_back(nc); + ret[nc.myId].push_back(nc); return ret; } @@ -167,22 +212,15 @@ std::list CTU::loadUnsafeUsageListFromXml(const tiny for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) { if (std::strcmp(e->Name(), "unsafe-usage") != 0) continue; - const char *id = e->Attribute("id"); - if (!id) - continue; - const char *argnr = e->Attribute("argnr"); - if (!argnr || !MathLib::isInt(argnr)) - continue; - const char *argname = e->Attribute("argname"); - if (!argname) - continue; - const char *fileName = e->Attribute("fileName"); - if (!fileName) - continue; - const char *linenr = e->Attribute("linenr"); - if (!linenr || !MathLib::isInt(linenr)) - continue; - ret.push_back(FileInfo::UnsafeUsage(id, std::atoi(argnr), argname, FileInfo::Location(fileName, std::atoi(linenr)))); + bool error = false; + FileInfo::UnsafeUsage unsafeUsage; + unsafeUsage.myId = readAttrString(e, ATTR_MY_ID, &error); + unsafeUsage.myArgNr = readAttrInt(e, ATTR_MY_ARGNR, &error); + unsafeUsage.myArgumentName = readAttrString(e, ATTR_MY_ARGNAME, &error); + unsafeUsage.location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error); + unsafeUsage.location.linenr = readAttrInt(e, ATTR_LOC_LINENR, &error); + if (!error) + ret.push_back(unsafeUsage); } return ret; } @@ -242,14 +280,14 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) continue; if (argtok->hasKnownIntValue()) { struct FileInfo::FunctionCall functionCall; - functionCall.valueType = ValueFlow::Value::INT; - functionCall.functionId = getFunctionId(tokenizer, tok->astOperand1()->function()); - functionCall.functionName = tok->astOperand1()->expressionString(); + functionCall.callValueType = ValueFlow::Value::INT; + functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); + functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.location.fileName = tokenizer->list.file(tok); functionCall.location.linenr = tok->linenr(); - functionCall.argnr = argnr + 1; - functionCall.argumentExpression = argtok->expressionString(); - functionCall.argvalue = argtok->values().front().intvalue; + functionCall.callArgNr = argnr + 1; + functionCall.callArgumentExpression = argtok->expressionString(); + functionCall.callArgValue = argtok->values().front().intvalue; fileInfo->functionCalls.push_back(functionCall); continue; } @@ -264,14 +302,14 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) const ValueFlow::Value &v = argtok->values().front(); if (v.valueType == ValueFlow::Value::UNINIT && !v.isInconclusive()) { struct FileInfo::FunctionCall functionCall; - functionCall.valueType = ValueFlow::Value::UNINIT; - functionCall.functionId = getFunctionId(tokenizer, tok->astOperand1()->function()); - functionCall.functionName = tok->astOperand1()->expressionString(); + functionCall.callValueType = ValueFlow::Value::UNINIT; + functionCall.callId = getFunctionId(tokenizer, tok->astOperand1()->function()); + functionCall.callFunctionName = tok->astOperand1()->expressionString(); functionCall.location.fileName = tokenizer->list.file(tok); functionCall.location.linenr = tok->linenr(); - functionCall.argnr = argnr + 1; - functionCall.argvalue = 0; - functionCall.argumentExpression = argtok->expressionString(); + functionCall.callArgNr = argnr + 1; + functionCall.callArgValue = 0; + functionCall.callArgumentExpression = argtok->expressionString(); fileInfo->functionCalls.push_back(functionCall); continue; } @@ -283,10 +321,9 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer) const Token *tok; int argnr2 = isCallFunction(&scope, argnr, &tok); if (argnr2 > 0) { - FileInfo::NestedCall nestedCall(tokenizer, &scope, argnr+1, tok); - nestedCall.id = getFunctionId(tokenizer, function); - nestedCall.id2 = getFunctionId(tokenizer, tok->function()); - nestedCall.argnr2 = argnr2; + FileInfo::NestedCall nestedCall(tokenizer, function, tok); + nestedCall.myArgNr = argnr + 1; + nestedCall.callArgNr = argnr2; fileInfo->nestedCalls.push_back(nestedCall); } } @@ -345,15 +382,15 @@ static bool findPath(const CTU::FileInfo::FunctionCall &from, const CTU::FileInfo::UnsafeUsage &to, const std::map> &nestedCalls) { - if (from.functionId == to.functionId && from.argnr == to.argnr) + if (from.callId == to.myId && from.callArgNr == to.myArgNr) return true; - const std::map>::const_iterator nc = nestedCalls.find(from.functionId); + const std::map>::const_iterator nc = nestedCalls.find(from.callId); if (nc == nestedCalls.end()) return false; for (const CTU::FileInfo::NestedCall &nestedCall : nc->second) { - if (from.functionId == nestedCall.id && from.argnr == nestedCall.argnr && nestedCall.id2 == to.functionId && nestedCall.argnr2 == to.argnr) + if (from.callId == nestedCall.myId && from.callArgNr == nestedCall.myArgNr && nestedCall.callId == to.myId && nestedCall.callArgNr == to.myArgNr) return true; } @@ -371,11 +408,11 @@ std::list CTU::FileInfo::getErrorPath(I for (const FunctionCall &functionCall : functionCalls) { if (invalidValue == CTU::FileInfo::InvalidValueType::null && - (functionCall.valueType != ValueFlow::Value::ValueType::INT || functionCall.argvalue != 0)) { + (functionCall.callValueType != ValueFlow::Value::ValueType::INT || functionCall.callArgValue != 0)) { continue; } if (invalidValue == CTU::FileInfo::InvalidValueType::uninit && - functionCall.valueType != ValueFlow::Value::ValueType::UNINIT) { + functionCall.callValueType != ValueFlow::Value::ValueType::UNINIT) { continue; } @@ -386,20 +423,20 @@ std::list CTU::FileInfo::getErrorPath(I *functionCallPtr = &functionCall; std::string value1; - if (functionCall.valueType == ValueFlow::Value::ValueType::INT) + if (functionCall.callValueType == ValueFlow::Value::ValueType::INT) value1 = "null"; - else if (functionCall.valueType == ValueFlow::Value::ValueType::UNINIT) + else if (functionCall.callValueType == ValueFlow::Value::ValueType::UNINIT) value1 = "uninitialized"; ErrorLogger::ErrorMessage::FileLocation fileLoc1; fileLoc1.setfile(functionCall.location.fileName); fileLoc1.line = functionCall.location.linenr; - fileLoc1.setinfo("Calling function " + functionCall.functionName + ", " + MathLib::toString(functionCall.argnr) + getOrdinalText(functionCall.argnr) + " argument is " + value1); + fileLoc1.setinfo("Calling function " + functionCall.callFunctionName + ", " + MathLib::toString(functionCall.callArgNr) + getOrdinalText(functionCall.callArgNr) + " argument is " + value1); ErrorLogger::ErrorMessage::FileLocation fileLoc2; fileLoc2.setfile(unsafeUsage.location.fileName); fileLoc2.line = unsafeUsage.location.linenr; - fileLoc2.setinfo(replaceStr(info, "ARG", unsafeUsage.argumentName)); + fileLoc2.setinfo(replaceStr(info, "ARG", unsafeUsage.myArgumentName)); locationList.push_back(fileLoc1); locationList.push_back(fileLoc2); diff --git a/lib/ctu.h b/lib/ctu.h index b9268b71a..c476ea91e 100644 --- a/lib/ctu.h +++ b/lib/ctu.h @@ -45,44 +45,57 @@ namespace CTU { struct UnsafeUsage { UnsafeUsage() = default; - UnsafeUsage(const std::string &functionId, unsigned int argnr, const std::string &argumentName, const Location &location) : functionId(functionId), argnr(argnr), argumentName(argumentName), location(location) {} - std::string functionId; - unsigned int argnr; - std::string argumentName; + UnsafeUsage(const std::string &myId, unsigned int myArgNr, const std::string &myArgumentName, const Location &location) : myId(myId), myArgNr(myArgNr), myArgumentName(myArgumentName), location(location) {} + std::string myId; + unsigned int myArgNr; + std::string myArgumentName; Location location; std::string toString() const; }; - struct FunctionCall { - std::string functionId; - std::string functionName; - std::string argumentExpression; - unsigned int argnr; - long long argvalue; - ValueFlow::Value::ValueType valueType; + class CallBase { + public: + CallBase() = default; + CallBase(const std::string &callId, int callArgNr, const std::string &callFunctionName, const Location &loc) + : callId(callId), callArgNr(callArgNr), callFunctionName(callFunctionName), location(loc) + {} + CallBase(const Tokenizer *tokenizer, const Token *callToken); + std::string callId; + int callArgNr; + std::string callFunctionName; Location location; + protected: + std::string toBaseXmlString() const; + bool loadBaseFromXml(const tinyxml2::XMLElement *xmlElement); }; - struct NestedCall { + class FunctionCall : public CallBase { + public: + std::string callArgumentExpression; + long long callArgValue; + ValueFlow::Value::ValueType callValueType; + + std::string toXmlString() const; + bool loadFromXml(const tinyxml2::XMLElement *xmlElement); + }; + + class NestedCall : public CallBase { + public: NestedCall() = default; - NestedCall(const std::string &id_, const std::string &functionName_, unsigned int argnr_, const std::string &fileName, unsigned int linenr) - : id(id_), - functionName(functionName_), - argnr(argnr_), - argnr2(0) { - location.fileName = fileName; - location.linenr = linenr; + NestedCall(const std::string &myId, unsigned int myArgNr, const std::string &callId, unsigned int callArgnr, const std::string &callFunctionName, const Location &location) + : CallBase(callId, callArgnr, callFunctionName, location), + myId(myId), + myArgNr(myArgNr) { } - NestedCall(const Tokenizer *tokenizer, const Scope *scope, unsigned int argnr_, const Token *tok); + NestedCall(const Tokenizer *tokenizer, const Function *myFunction, const Token *callToken); - std::string id; - std::string id2; - std::string functionName; - unsigned int argnr; - unsigned int argnr2; - Location location; + std::string toXmlString() const; + bool loadFromXml(const tinyxml2::XMLElement *xmlElement); + + std::string myId; + unsigned int myArgNr; }; std::list functionCalls;