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 {
class TrackExecution {
public:
TrackExecution() : mDataIndex(0) {}
TrackExecution() : mDataIndex(0), mAbortLine(-1) {}
std::map<const Token *, std::vector<std::string>> 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<std::string> mSymbols;
std::set<int> mErrors;
};
class Data : public ExprEngine::DataBase {
@ -132,6 +171,10 @@ namespace {
const std::vector<ExprEngine::Callback> &callbacks;
std::vector<ExprEngine::ValuePtr> 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<BailoutValue>();
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<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->reportErr(errmsg);

View File

@ -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<void(const Token *, const ExprEngine::Value &, ExprEngine::DataBase *)> Callback;
/** Execute all functions */