CTU: Find paths better
This commit is contained in:
parent
b3fcd8a685
commit
c8901e9bab
|
@ -653,7 +653,7 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std::
|
||||||
bool foundErrors = false;
|
bool foundErrors = false;
|
||||||
(void)settings; // This argument is unused
|
(void)settings; // This argument is unused
|
||||||
|
|
||||||
const std::map<std::string, std::list<CTU::FileInfo::NestedCall>> nestedCallsMap = ctu->getNestedCallsMap();
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> callsMap = ctu->getCallsMap();
|
||||||
|
|
||||||
for (Check::FileInfo *fi1 : fileInfo) {
|
for (Check::FileInfo *fi1 : fileInfo) {
|
||||||
const MyFileInfo *fi = dynamic_cast<MyFileInfo*>(fi1);
|
const MyFileInfo *fi = dynamic_cast<MyFileInfo*>(fi1);
|
||||||
|
@ -663,7 +663,7 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo *ctu, const std::
|
||||||
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,
|
||||||
nestedCallsMap,
|
callsMap,
|
||||||
"Dereferencing argument ARG that is null",
|
"Dereferencing argument ARG that is null",
|
||||||
nullptr);
|
nullptr);
|
||||||
if (locationList.empty())
|
if (locationList.empty())
|
||||||
|
|
|
@ -1325,7 +1325,7 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo *ctu, const std::li
|
||||||
bool foundErrors = false;
|
bool foundErrors = false;
|
||||||
(void)settings; // This argument is unused
|
(void)settings; // This argument is unused
|
||||||
|
|
||||||
const std::map<std::string, std::list<CTU::FileInfo::NestedCall>> nestedCallsMap = ctu->getNestedCallsMap();
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> callsMap = ctu->getCallsMap();
|
||||||
|
|
||||||
for (Check::FileInfo *fi1 : fileInfo) {
|
for (Check::FileInfo *fi1 : fileInfo) {
|
||||||
const MyFileInfo *fi = dynamic_cast<MyFileInfo*>(fi1);
|
const MyFileInfo *fi = dynamic_cast<MyFileInfo*>(fi1);
|
||||||
|
@ -1337,7 +1337,7 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo *ctu, const std::li
|
||||||
const std::list<ErrorLogger::ErrorMessage::FileLocation> &locationList =
|
const std::list<ErrorLogger::ErrorMessage::FileLocation> &locationList =
|
||||||
ctu->getErrorPath(CTU::FileInfo::InvalidValueType::uninit,
|
ctu->getErrorPath(CTU::FileInfo::InvalidValueType::uninit,
|
||||||
unsafeUsage,
|
unsafeUsage,
|
||||||
nestedCallsMap,
|
callsMap,
|
||||||
"Using argument ARG",
|
"Using argument ARG",
|
||||||
&functionCall);
|
&functionCall);
|
||||||
if (locationList.empty())
|
if (locationList.empty())
|
||||||
|
|
116
lib/ctu.cpp
116
lib/ctu.cpp
|
@ -198,11 +198,13 @@ void CTU::FileInfo::loadFromXml(const tinyxml2::XMLElement *xmlElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::list<CTU::FileInfo::NestedCall>> CTU::FileInfo::getNestedCallsMap() const
|
std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> CTU::FileInfo::getCallsMap() const
|
||||||
{
|
{
|
||||||
std::map<std::string, std::list<CTU::FileInfo::NestedCall>> ret;
|
std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> ret;
|
||||||
for (const CTU::FileInfo::NestedCall &nc : nestedCalls)
|
for (const CTU::FileInfo::NestedCall &nc : nestedCalls)
|
||||||
ret[nc.myId].push_back(nc);
|
ret[nc.callId].push_back(&nc);
|
||||||
|
for (const CTU::FileInfo::FunctionCall &fc : functionCalls)
|
||||||
|
ret[fc.callId].push_back(&fc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,20 +380,48 @@ std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *token
|
||||||
return unsafeUsage;
|
return unsafeUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool findPath(const CTU::FileInfo::FunctionCall &from,
|
static bool findPath(const std::string &callId,
|
||||||
const CTU::FileInfo::UnsafeUsage &to,
|
unsigned int callArgNr,
|
||||||
const std::map<std::string, std::list<CTU::FileInfo::NestedCall>> &nestedCalls)
|
CTU::FileInfo::InvalidValueType invalidValue,
|
||||||
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
|
||||||
|
const CTU::FileInfo::CallBase *path[10],
|
||||||
|
int index)
|
||||||
{
|
{
|
||||||
if (from.callId == to.myId && from.callArgNr == to.myArgNr)
|
if (index >= 10)
|
||||||
return true;
|
|
||||||
|
|
||||||
const std::map<std::string, std::list<CTU::FileInfo::NestedCall>>::const_iterator nc = nestedCalls.find(from.callId);
|
|
||||||
if (nc == nestedCalls.end())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (const CTU::FileInfo::NestedCall &nestedCall : nc->second) {
|
const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>>::const_iterator it = callsMap.find(callId);
|
||||||
if (from.callId == nestedCall.myId && from.callArgNr == nestedCall.myArgNr && nestedCall.callId == to.myId && nestedCall.callArgNr == to.myArgNr)
|
if (it == callsMap.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const CTU::FileInfo::CallBase *c : it->second) {
|
||||||
|
if (c->callArgNr != callArgNr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
|
||||||
|
if (functionCall) {
|
||||||
|
switch (invalidValue) {
|
||||||
|
case CTU::FileInfo::InvalidValueType::null:
|
||||||
|
if (functionCall->callValueType != ValueFlow::Value::INT || functionCall->callArgValue != 0)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case CTU::FileInfo::InvalidValueType::uninit:
|
||||||
|
if (functionCall->callValueType != ValueFlow::Value::UNINIT)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
path[index] = functionCall;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTU::FileInfo::NestedCall *nestedCall = dynamic_cast<const CTU::FileInfo::NestedCall *>(c);
|
||||||
|
if (!nestedCall)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (findPath(nestedCall->myId, nestedCall->myArgNr, invalidValue, callsMap, path, index + 1)) {
|
||||||
|
path[index] = nestedCall;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -399,50 +429,38 @@ static bool findPath(const CTU::FileInfo::FunctionCall &from,
|
||||||
|
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueType invalidValue,
|
std::list<ErrorLogger::ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueType invalidValue,
|
||||||
const CTU::FileInfo::UnsafeUsage &unsafeUsage,
|
const CTU::FileInfo::UnsafeUsage &unsafeUsage,
|
||||||
const std::map<std::string, std::list<CTU::FileInfo::NestedCall>> &nestedCallsMap,
|
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) const
|
||||||
{
|
{
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
std::list<ErrorLogger::ErrorMessage::FileLocation> locationList;
|
||||||
|
|
||||||
for (const FunctionCall &functionCall : functionCalls) {
|
const CTU::FileInfo::CallBase *path[10] = {0};
|
||||||
|
|
||||||
if (invalidValue == CTU::FileInfo::InvalidValueType::null &&
|
|
||||||
(functionCall.callValueType != ValueFlow::Value::ValueType::INT || functionCall.callArgValue != 0)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (invalidValue == CTU::FileInfo::InvalidValueType::uninit &&
|
|
||||||
functionCall.callValueType != ValueFlow::Value::ValueType::UNINIT) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!findPath(functionCall, unsafeUsage, nestedCallsMap))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (functionCallPtr)
|
|
||||||
*functionCallPtr = &functionCall;
|
|
||||||
|
|
||||||
std::string value1;
|
|
||||||
if (functionCall.callValueType == ValueFlow::Value::ValueType::INT)
|
|
||||||
value1 = "null";
|
|
||||||
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.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.myArgumentName));
|
|
||||||
|
|
||||||
locationList.push_back(fileLoc1);
|
|
||||||
locationList.push_back(fileLoc2);
|
|
||||||
|
|
||||||
|
if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, invalidValue, callsMap, path, 0))
|
||||||
return locationList;
|
return locationList;
|
||||||
|
|
||||||
|
const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
|
||||||
|
|
||||||
|
for (int index = 9; index >= 0; index--) {
|
||||||
|
if (!path[index])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (functionCallPtr && !*functionCallPtr)
|
||||||
|
*functionCallPtr = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
|
||||||
|
|
||||||
|
ErrorLogger::ErrorMessage::FileLocation fileLoc;
|
||||||
|
fileLoc.setfile(path[index]->location.fileName);
|
||||||
|
fileLoc.line = path[index]->location.linenr;
|
||||||
|
fileLoc.setinfo("Calling function " + path[index]->callFunctionName + ", " + MathLib::toString(path[index]->callArgNr) + getOrdinalText(path[index]->callArgNr) + " argument is " + value1);
|
||||||
|
locationList.push_back(fileLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorLogger::ErrorMessage::FileLocation fileLoc2;
|
||||||
|
fileLoc2.setfile(unsafeUsage.location.fileName);
|
||||||
|
fileLoc2.line = unsafeUsage.location.linenr;
|
||||||
|
fileLoc2.setinfo(replaceStr(info, "ARG", unsafeUsage.myArgumentName));
|
||||||
|
locationList.push_back(fileLoc2);
|
||||||
|
|
||||||
return locationList;
|
return locationList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
namespace CTU {
|
namespace CTU {
|
||||||
class CPPCHECKLIB FileInfo : public Check::FileInfo {
|
class CPPCHECKLIB FileInfo : public Check::FileInfo {
|
||||||
public:
|
public:
|
||||||
|
enum InvalidValueType { null, uninit };
|
||||||
|
|
||||||
std::string toString() const override;
|
std::string toString() const override;
|
||||||
|
|
||||||
struct Location {
|
struct Location {
|
||||||
|
@ -60,6 +62,7 @@ namespace CTU {
|
||||||
: callId(callId), callArgNr(callArgNr), callFunctionName(callFunctionName), location(loc)
|
: callId(callId), callArgNr(callArgNr), callFunctionName(callFunctionName), location(loc)
|
||||||
{}
|
{}
|
||||||
CallBase(const Tokenizer *tokenizer, const Token *callToken);
|
CallBase(const Tokenizer *tokenizer, const Token *callToken);
|
||||||
|
virtual ~CallBase() {}
|
||||||
std::string callId;
|
std::string callId;
|
||||||
int callArgNr;
|
int callArgNr;
|
||||||
std::string callFunctionName;
|
std::string callFunctionName;
|
||||||
|
@ -102,13 +105,11 @@ namespace CTU {
|
||||||
std::list<NestedCall> nestedCalls;
|
std::list<NestedCall> nestedCalls;
|
||||||
|
|
||||||
void loadFromXml(const tinyxml2::XMLElement *xmlElement);
|
void loadFromXml(const tinyxml2::XMLElement *xmlElement);
|
||||||
std::map<std::string, std::list<NestedCall>> getNestedCallsMap() const;
|
std::map<std::string, std::list<const CallBase *>> getCallsMap() const;
|
||||||
|
|
||||||
enum InvalidValueType { null, uninit };
|
|
||||||
|
|
||||||
std::list<ErrorLogger::ErrorMessage::FileLocation> getErrorPath(InvalidValueType invalidValue,
|
std::list<ErrorLogger::ErrorMessage::FileLocation> getErrorPath(InvalidValueType invalidValue,
|
||||||
const UnsafeUsage &unsafeUsage,
|
const UnsafeUsage &unsafeUsage,
|
||||||
const std::map<std::string, std::list<NestedCall>> &nestedCallsMap,
|
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) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2715,6 +2715,7 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("test.cpp:1:error:Null pointer dereference: p\n"
|
ASSERT_EQUALS("test.cpp:1:error:Null pointer dereference: p\n"
|
||||||
"test.cpp:4:note:Calling function call, 2nd argument is null\n"
|
"test.cpp:4:note:Calling function call, 2nd argument is null\n"
|
||||||
|
"test.cpp:2:note:Calling function use, 1st argument is null\n"
|
||||||
"test.cpp:1:note:Dereferencing argument p that is null\n", errout.str());
|
"test.cpp:1:note:Dereferencing argument p that is null\n", errout.str());
|
||||||
|
|
||||||
ctu("void dostuff(int *x, int *y) {\n"
|
ctu("void dostuff(int *x, int *y) {\n"
|
||||||
|
|
|
@ -4056,7 +4056,7 @@ private:
|
||||||
" int x;\n"
|
" int x;\n"
|
||||||
" call(4,&x);\n"
|
" call(4,&x);\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:1]: (error) Using argument p that points at uninitialized variable x\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:2] -> [test.cpp:1]: (error) Using argument p that points at uninitialized variable x\n", errout.str());
|
||||||
|
|
||||||
ctu("void dostuff(int *x, int *y) {\n"
|
ctu("void dostuff(int *x, int *y) {\n"
|
||||||
" if (!var)\n"
|
" if (!var)\n"
|
||||||
|
|
Loading…
Reference in New Issue