From 93f10da9815176447eee6d76dd914139991548b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 22 Dec 2019 21:00:53 +0100 Subject: [PATCH] Verification; Detect errors after bailout --- lib/exprengine.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++-- lib/exprengine.h | 14 ++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp index 079eb2be5..495777d5b 100644 --- a/lib/exprengine.cpp +++ b/lib/exprengine.cpp @@ -68,7 +68,7 @@ static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, namespace { class TrackExecution { public: - TrackExecution() : mDataIndex(0) {} + TrackExecution() : mDataIndex(0), mAbortLine(-1) {} std::map> map; int getNewDataIndex() { return mDataIndex++; @@ -111,9 +111,48 @@ namespace { } } } + + void report(std::ostream &out, const Scope *functionScope) { + int linenr = -1; + std::string code; + for (const Token *tok = functionScope->bodyStart->next(); tok != functionScope->bodyEnd; tok = tok->next()) { + if (tok->linenr() > linenr) { + if (!code.empty()) + out << getStatus(linenr) << " " << code << std::endl; + linenr = tok->linenr(); + code.clear(); + } + code += " " + tok->str(); + } + + out << getStatus(linenr) << " " << code << std::endl; + } + + void setAbortLine(int linenr) { + if (linenr > 0 && (mAbortLine == -1 || linenr < mAbortLine)) + mAbortLine = linenr; + } + + void addError(int linenr) { + mErrors.insert(linenr); + } + + bool isAllOk() const { + return mErrors.empty(); + } private: + const char *getStatus(int linenr) const { + if (mErrors.find(linenr) != mErrors.end()) + return "ERROR"; + if (mAbortLine > 0 && linenr >= mAbortLine) + return "--"; + return "ok"; + } + int mDataIndex; + int mAbortLine; std::set mSymbols; + std::set mErrors; }; class Data : public ExprEngine::DataBase { @@ -132,6 +171,10 @@ namespace { const std::vector &callbacks; std::vector constraints; + void addError(int linenr) OVERRIDE { + mTrackExecution->addError(linenr); + } + void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) { if (varId == 0) return; @@ -1446,12 +1489,23 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to for (const Variable &arg : function->argumentList) data.assignValue(functionScope->bodyStart, arg.declarationId(), createVariableValue(arg, data)); - execute(functionScope->bodyStart, functionScope->bodyEnd, data); + try { + execute(functionScope->bodyStart, functionScope->bodyEnd, data); + } catch (VerifyException &e) { + trackExecution.setAbortLine(e.tok->linenr()); + auto bailoutValue = std::make_shared(); + for (const Token *tok = e.tok; tok != functionScope->bodyEnd; tok = tok->next()) + call(callbacks, tok, bailoutValue, &data); + } if (settings->debugVerification) { // TODO generate better output!! trackExecution.print(trace); } + + // Write a verification report + //if (!trackExecution.isAllOk()) + // trackExecution.report(trace, functionScope); } void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings) @@ -1460,6 +1514,7 @@ void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, if (!tok->astParent() || !std::strchr("/%", tok->astParent()->str()[0])) return; if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) { + dataBase->addError(tok->linenr()); std::list callstack{tok->astParent()}; ErrorLogger::ErrorMessage errmsg(callstack, &tokenizer->list, Severity::SeverityType::error, "verificationDivByZero", "There is division, cannot determine that there can't be a division by zero.", CWE(369), false); errorLogger->reportErr(errmsg); diff --git a/lib/exprengine.h b/lib/exprengine.h index d0205c72f..84d665a43 100644 --- a/lib/exprengine.h +++ b/lib/exprengine.h @@ -64,7 +64,8 @@ namespace ExprEngine { StructValue, AddressOfValue, BinOpResult, - IntegerTruncation + IntegerTruncation, + BailoutValue }; class Value; @@ -75,6 +76,9 @@ namespace ExprEngine { explicit DataBase(const Settings *settings) : settings(settings) {} virtual std::string getNewSymbolName() = 0; const Settings * const settings; + virtual void addError(int linenr) { + (void)linenr; + } }; class Value { @@ -280,6 +284,14 @@ namespace ExprEngine { char sign; }; + class BailoutValue : public Value { + public: + BailoutValue() : Value("bailout", ValueType::BailoutValue) {} + bool isEqual(DataBase * /*dataBase*/, int /*value*/) const { + return true; + } + }; + typedef std::function Callback; /** Execute all functions */