Verification; Detect errors after bailout

This commit is contained in:
Daniel Marjamäki 2019-12-22 21:00:53 +01:00
parent 5715ba7ce0
commit 93f10da981
2 changed files with 70 additions and 3 deletions

View File

@ -68,7 +68,7 @@ static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name,
namespace { namespace {
class TrackExecution { class TrackExecution {
public: public:
TrackExecution() : mDataIndex(0) {} TrackExecution() : mDataIndex(0), mAbortLine(-1) {}
std::map<const Token *, std::vector<std::string>> map; std::map<const Token *, std::vector<std::string>> map;
int getNewDataIndex() { int getNewDataIndex() {
return mDataIndex++; 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: 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 mDataIndex;
int mAbortLine;
std::set<std::string> mSymbols; std::set<std::string> mSymbols;
std::set<int> mErrors;
}; };
class Data : public ExprEngine::DataBase { class Data : public ExprEngine::DataBase {
@ -132,6 +171,10 @@ namespace {
const std::vector<ExprEngine::Callback> &callbacks; const std::vector<ExprEngine::Callback> &callbacks;
std::vector<ExprEngine::ValuePtr> constraints; std::vector<ExprEngine::ValuePtr> constraints;
void addError(int linenr) OVERRIDE {
mTrackExecution->addError(linenr);
}
void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) { void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) {
if (varId == 0) if (varId == 0)
return; return;
@ -1446,12 +1489,23 @@ void ExprEngine::executeFunction(const Scope *functionScope, const Tokenizer *to
for (const Variable &arg : function->argumentList) for (const Variable &arg : function->argumentList)
data.assignValue(functionScope->bodyStart, arg.declarationId(), createVariableValue(arg, data)); 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<BailoutValue>();
for (const Token *tok = e.tok; tok != functionScope->bodyEnd; tok = tok->next())
call(callbacks, tok, bailoutValue, &data);
}
if (settings->debugVerification) { if (settings->debugVerification) {
// TODO generate better output!! // TODO generate better output!!
trackExecution.print(trace); 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) 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])) if (!tok->astParent() || !std::strchr("/%", tok->astParent()->str()[0]))
return; return;
if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) { if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) {
dataBase->addError(tok->linenr());
std::list<const Token*> callstack{tok->astParent()}; std::list<const Token*> 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::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); errorLogger->reportErr(errmsg);

View File

@ -64,7 +64,8 @@ namespace ExprEngine {
StructValue, StructValue,
AddressOfValue, AddressOfValue,
BinOpResult, BinOpResult,
IntegerTruncation IntegerTruncation,
BailoutValue
}; };
class Value; class Value;
@ -75,6 +76,9 @@ namespace ExprEngine {
explicit DataBase(const Settings *settings) : settings(settings) {} explicit DataBase(const Settings *settings) : settings(settings) {}
virtual std::string getNewSymbolName() = 0; virtual std::string getNewSymbolName() = 0;
const Settings * const settings; const Settings * const settings;
virtual void addError(int linenr) {
(void)linenr;
}
}; };
class Value { class Value {
@ -280,6 +284,14 @@ namespace ExprEngine {
char sign; char sign;
}; };
class BailoutValue : public Value {
public:
BailoutValue() : Value("bailout", ValueType::BailoutValue) {}
bool isEqual(DataBase * /*dataBase*/, int /*value*/) const {
return true;
}
};
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 */