Verification; Updated report

This commit is contained in:
Daniel Marjamäki 2019-12-27 19:05:10 +01:00
parent 147cf9319f
commit 4b4f7ea60b
17 changed files with 89 additions and 26 deletions

View File

@ -192,6 +192,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
// Experimental: Verify // Experimental: Verify
else if (std::strcmp(argv[i], "--verify") == 0) else if (std::strcmp(argv[i], "--verify") == 0)
mSettings->verification = true; mSettings->verification = true;
else if (std::strcmp(argv[i], "--verify-report") == 0)
mSettings->verification = mSettings->verificationReport = true;
else if (std::strcmp(argv[i], "--debug-verify") == 0) else if (std::strcmp(argv[i], "--debug-verify") == 0)
mSettings->debugVerification = true; mSettings->debugVerification = true;

View File

@ -79,13 +79,14 @@
/*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout; /*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout;
CppCheckExecutor::CppCheckExecutor() CppCheckExecutor::CppCheckExecutor()
: mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mShowAllErrors(false) : mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mVerificationOutput(nullptr), mShowAllErrors(false)
{ {
} }
CppCheckExecutor::~CppCheckExecutor() CppCheckExecutor::~CppCheckExecutor()
{ {
delete mErrorOutput; delete mErrorOutput;
delete mVerificationOutput;
} }
bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[]) bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[])
@ -1063,6 +1064,13 @@ void CppCheckExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
} }
} }
void CppCheckExecutor::reportVerification(const std::string &str)
{
if (!mVerificationOutput)
mVerificationOutput = new std::ofstream("verification-report.txt");
(*mVerificationOutput) << str << std::endl;
}
void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput)
{ {
mExceptionOutput = exceptionOutput; mExceptionOutput = exceptionOutput;

View File

@ -81,6 +81,8 @@ public:
*/ */
void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE; void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
void reportVerification(const std::string &str) OVERRIDE;
/** /**
* Information about how many files have been checked * Information about how many files have been checked
* *
@ -187,6 +189,11 @@ private:
*/ */
std::ofstream *mErrorOutput; std::ofstream *mErrorOutput;
/**
* Verification report
*/
std::ostream *mVerificationOutput;
/** /**
* Has --errorlist been given? * Has --errorlist been given?
*/ */

View File

@ -348,6 +348,11 @@ void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
writeToPipe(REPORT_INFO, msg.serialize()); writeToPipe(REPORT_INFO, msg.serialize());
} }
void ThreadExecutor::reportVerification(const std::string &str)
{
writeToPipe(REPORT_VERIFICATION, str.c_str());
}
#elif defined(THREADING_MODEL_WIN) #elif defined(THREADING_MODEL_WIN)
void ThreadExecutor::addFileContent(const std::string &path, const std::string &content) void ThreadExecutor::addFileContent(const std::string &path, const std::string &content)
@ -490,7 +495,12 @@ void ThreadExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg) void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
{ {
report(msg, MessageType::REPORT_INFO);
}
void ThreadExecutor::reportVerification(const std::string &/*str*/)
{
// TODO
} }
void ThreadExecutor::report(const ErrorLogger::ErrorMessage &msg, MessageType msgType) void ThreadExecutor::report(const ErrorLogger::ErrorMessage &msg, MessageType msgType)
@ -551,4 +561,8 @@ void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &/*msg*/)
} }
void ThreadExecutor::reportVerification(const std::string &/*str*/)
{
}
#endif #endif

View File

@ -54,6 +54,7 @@ public:
void reportOut(const std::string &outmsg) OVERRIDE; void reportOut(const std::string &outmsg) OVERRIDE;
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE; void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE; void reportInfo(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
void reportVerification(const std::string &str) OVERRIDE;
/** /**
* @brief Add content to a file, to be used in unit testing. * @brief Add content to a file, to be used in unit testing.
@ -75,7 +76,7 @@ private:
/** @brief Key is file name, and value is the content of the file */ /** @brief Key is file name, and value is the content of the file */
std::map<std::string, std::string> mFileContents; std::map<std::string, std::string> mFileContents;
private: private:
enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', CHILD_END='4'}; enum PipeSignal {REPORT_OUT='1',REPORT_ERROR='2', REPORT_INFO='3', REPORT_VERIFICATION='4', CHILD_END='5'};
/** /**
* Read from the pipe, parse and handle what ever is in there. * Read from the pipe, parse and handle what ever is in there.

View File

@ -12,10 +12,11 @@ NewSuppressionDialog::NewSuppressionDialog(QWidget *parent) :
class QErrorLogger : public ErrorLogger { class QErrorLogger : public ErrorLogger {
public: public:
virtual void reportOut(const std::string &/*outmsg*/) {} void reportOut(const std::string &/*outmsg*/) override {}
virtual void reportErr(const ErrorLogger::ErrorMessage &msg) { void reportErr(const ErrorLogger::ErrorMessage &msg) override {
errorIds << QString::fromStdString(msg.id); errorIds << QString::fromStdString(msg.id);
} }
void reportVerification(const std::string &/*str*/) override {}
QStringList errorIds; QStringList errorIds;
}; };

View File

@ -74,6 +74,7 @@ public:
*/ */
void reportOut(const std::string &outmsg) override; void reportOut(const std::string &outmsg) override;
void reportErr(const ErrorLogger::ErrorMessage &msg) override; void reportErr(const ErrorLogger::ErrorMessage &msg) override;
void reportVerification(const std::string &/*str*/) override {}
public slots: public slots:

View File

@ -766,9 +766,8 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer)
} }
// Verification using ExprEngine.. // Verification using ExprEngine..
if (mSettings.verification) { if (mSettings.verification)
ExprEngine::runChecks(this, &tokenizer, &mSettings); ExprEngine::runChecks(this, &tokenizer, &mSettings);
}
// Analyse the tokens.. // Analyse the tokens..
@ -1202,6 +1201,11 @@ void CppCheck::reportStatus(unsigned int /*fileindex*/, unsigned int /*filecount
} }
void CppCheck::reportVerification(const std::string &str)
{
mErrorLogger.reportVerification(str);
}
void CppCheck::getErrorMessages() void CppCheck::getErrorMessages()
{ {
Settings s(mSettings); Settings s(mSettings);

View File

@ -195,6 +195,8 @@ private:
*/ */
void reportOut(const std::string &outmsg) OVERRIDE; void reportOut(const std::string &outmsg) OVERRIDE;
void reportVerification(const std::string &str) OVERRIDE;
std::list<std::string> mErrorList; std::list<std::string> mErrorList;
Settings mSettings; Settings mSettings;

View File

@ -401,6 +401,8 @@ public:
reportErr(msg); reportErr(msg);
} }
virtual void reportVerification(const std::string &str) = 0;
/** /**
* Report unmatched suppressions * Report unmatched suppressions
* @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions)

View File

@ -18,6 +18,7 @@
#include "exprengine.h" #include "exprengine.h"
#include "astutils.h" #include "astutils.h"
#include "path.h"
#include "settings.h" #include "settings.h"
#include "symboldatabase.h" #include "symboldatabase.h"
#include "tokenize.h" #include "tokenize.h"
@ -1455,12 +1456,12 @@ static void execute(const Token *start, const Token *end, Data &data)
} }
} }
void ExprEngine::executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &trace) void ExprEngine::executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
{ {
const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase();
for (const Scope *functionScope : symbolDatabase->functionScopes) { for (const Scope *functionScope : symbolDatabase->functionScopes) {
try { try {
executeFunction(functionScope, tokenizer, settings, callbacks, trace); executeFunction(functionScope, tokenizer, settings, callbacks, report);
} catch (const VerifyException &e) { } catch (const VerifyException &e) {
// FIXME.. there should not be exceptions // FIXME.. there should not be exceptions
std::string functionName = functionScope->function->name(); std::string functionName = functionScope->function->name();
@ -1549,7 +1550,7 @@ static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data)
return ExprEngine::ValuePtr(); return ExprEngine::ValuePtr();
} }
void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &trace) void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<ExprEngine::Callback> &callbacks, std::ostream &report)
{ {
if (!functionScope->bodyStart) if (!functionScope->bodyStart)
return; return;
@ -1576,14 +1577,24 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to
call(callbacks, tok, bailoutValue, &data); call(callbacks, tok, bailoutValue, &data);
} }
if (settings->debugVerification) { if (settings->debugVerification && !trackExecution.isAllOk()) {
// TODO generate better output!! if (settings->verificationReport)
trackExecution.print(trace); report << "[debug]" << std::endl;
trackExecution.print(report);
if (settings->verificationReport)
report << "[details]" << std::endl;
trackExecution.report(report, functionScope);
} }
// Write a verification report // Write a verification report
//if (!trackExecution.isAllOk()) if (settings->verificationReport) {
// trackExecution.report(trace, functionScope); report << "[function-report] "
<< Path::stripDirectoryPart(tokenizer->list.getFiles().at(functionScope->bodyStart->fileIndex())) << ":"
<< functionScope->bodyStart->linenr() << ":"
<< function->name()
<< (trackExecution.isAllOk() ? " is safe" : " is not safe")
<< std::endl;
}
} }
void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings) void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings)
@ -1752,5 +1763,9 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer,
#ifdef VERIFY_INTEGEROVERFLOW #ifdef VERIFY_INTEGEROVERFLOW
callbacks.push_back(integerOverflow); callbacks.push_back(integerOverflow);
#endif #endif
ExprEngine::executeAllFunctions(tokenizer, settings, callbacks, std::cout);
std::ostringstream report;
ExprEngine::executeAllFunctions(tokenizer, settings, callbacks, report);
if (errorLogger && settings->verificationReport && !report.str().empty())
errorLogger->reportVerification(report.str());
} }

View File

@ -297,8 +297,8 @@ namespace ExprEngine {
typedef std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback; typedef std::function<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback;
/** Execute all functions */ /** Execute all functions */
void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace); void CPPCHECKLIB executeAllFunctions(const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &report);
void executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &trace); void executeFunction(const Scope *functionScope, const Tokenizer *tokenizer, const Settings *settings, const std::vector<Callback> &callbacks, std::ostream &report);
void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings); void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings);
} }

View File

@ -46,6 +46,7 @@ Settings::Settings()
force(false), force(false),
inconclusive(false), inconclusive(false),
verification(false), verification(false),
verificationReport(false),
debugVerification(false), debugVerification(false),
inlineSuppressions(false), inlineSuppressions(false),
jobs(1), jobs(1),

View File

@ -191,6 +191,10 @@ public:
/** @brief Enable verification analysis */ /** @brief Enable verification analysis */
bool verification; bool verification;
/** @brief Generate verification report */
bool verificationReport;
/** @brief Generate verification debug output */
bool debugVerification; bool debugVerification;
/** @brief check unknown function return values */ /** @brief check unknown function return values */

View File

@ -37,8 +37,8 @@ private:
public: public:
std::list<std::string> id; std::list<std::string> id;
void reportOut(const std::string & /*outmsg*/) OVERRIDE { void reportOut(const std::string & /*outmsg*/) OVERRIDE {}
} void reportVerification(const std::string & /*str*/) OVERRIDE {}
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE { void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE {
id.push_back(msg.id); id.push_back(msg.id);

View File

@ -103,8 +103,8 @@ private:
}; };
std::vector<ExprEngine::Callback> callbacks; std::vector<ExprEngine::Callback> callbacks;
callbacks.push_back(f); callbacks.push_back(f);
std::ostringstream dummy; std::ostringstream trace;
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, dummy); ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, trace);
return ret; return ret;
} }
@ -126,8 +126,8 @@ private:
}; };
std::vector<ExprEngine::Callback> callbacks; std::vector<ExprEngine::Callback> callbacks;
callbacks.push_back(f); callbacks.push_back(f);
std::ostringstream dummy; std::ostringstream trace;
ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, dummy); ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, trace);
return ret; return ret;
} }
@ -139,9 +139,9 @@ private:
Tokenizer tokenizer(&settings, this); Tokenizer tokenizer(&settings, this);
std::istringstream istr(code); std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp"); tokenizer.tokenize(istr, "test.cpp");
std::vector<ExprEngine::Callback> dummy; std::vector<ExprEngine::Callback> callbacks;
std::ostringstream ret; std::ostringstream ret;
ExprEngine::executeAllFunctions(&tokenizer, &settings, dummy, ret); ExprEngine::executeAllFunctions(&tokenizer, &settings, callbacks, ret);
return ret.str(); return ret.str();
} }

View File

@ -82,6 +82,7 @@ protected:
void processOptions(const options& args); void processOptions(const options& args);
public: public:
void reportVerification(const std::string &/*str*/) OVERRIDE {}
void reportOut(const std::string &outmsg) OVERRIDE; void reportOut(const std::string &outmsg) OVERRIDE;
void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE; void reportErr(const ErrorLogger::ErrorMessage &msg) OVERRIDE;
void run(const std::string &str); void run(const std::string &str);