mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
"-O gen-C++" support for "assert" statements
This commit is contained in:
parent
4928e074d4
commit
81a9745fb3
5 changed files with 146 additions and 66 deletions
124
src/Stmt.cc
124
src/Stmt.cc
|
@ -164,6 +164,12 @@ const NullStmt* Stmt::AsNullStmt() const
|
||||||
return (const NullStmt*)this;
|
return (const NullStmt*)this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AssertStmt* Stmt::AsAssertStmt() const
|
||||||
|
{
|
||||||
|
CHECK_TAG(tag, STMT_ASSERT, "Stmt::AsAssertStmt", stmt_name)
|
||||||
|
return (const AssertStmt*)this;
|
||||||
|
}
|
||||||
|
|
||||||
bool Stmt::SetLocationInfo(const Location* start, const Location* end)
|
bool Stmt::SetLocationInfo(const Location* start, const Location* end)
|
||||||
{
|
{
|
||||||
if ( ! Obj::SetLocationInfo(start, end) )
|
if ( ! Obj::SetLocationInfo(start, end) )
|
||||||
|
@ -1866,6 +1872,13 @@ AssertStmt::AssertStmt(ExprPtr arg_cond, ExprPtr arg_msg)
|
||||||
|
|
||||||
if ( msg && ! IsString(msg->GetType()->Tag()) )
|
if ( msg && ! IsString(msg->GetType()->Tag()) )
|
||||||
msg->Error("message must be string");
|
msg->Error("message must be string");
|
||||||
|
|
||||||
|
zeek::ODesc desc;
|
||||||
|
desc.SetShort(true);
|
||||||
|
desc.SetQuotes(true);
|
||||||
|
cond->Describe(&desc);
|
||||||
|
|
||||||
|
cond_desc = desc.Description();
|
||||||
}
|
}
|
||||||
|
|
||||||
ValPtr AssertStmt::Exec(Frame* f, StmtFlowType& flow)
|
ValPtr AssertStmt::Exec(Frame* f, StmtFlowType& flow)
|
||||||
|
@ -1873,26 +1886,14 @@ ValPtr AssertStmt::Exec(Frame* f, StmtFlowType& flow)
|
||||||
RegisterAccess();
|
RegisterAccess();
|
||||||
flow = FLOW_NEXT;
|
flow = FLOW_NEXT;
|
||||||
|
|
||||||
static auto assertion_failure_hook = id::find_func("assertion_failure");
|
|
||||||
static auto assertion_result_hook = id::find_func("assertion_result");
|
static auto assertion_result_hook = id::find_func("assertion_result");
|
||||||
|
|
||||||
bool run_result_hook = assertion_result_hook && assertion_result_hook->HasEnabledBodies();
|
bool run_result_hook = assertion_result_hook && assertion_result_hook->HasEnabledBodies();
|
||||||
bool run_failure_hook = assertion_failure_hook && assertion_failure_hook->HasEnabledBodies();
|
|
||||||
|
|
||||||
auto assert_result = cond->Eval(f)->AsBool();
|
auto assert_result = cond->Eval(f)->AsBool();
|
||||||
|
|
||||||
if ( assert_result && ! run_result_hook )
|
if ( ! cond->Eval(f)->AsBool() || run_result_hook )
|
||||||
return Val::nil;
|
{
|
||||||
|
|
||||||
// Textual representation of cond from the AST.
|
|
||||||
static zeek::ODesc desc;
|
|
||||||
desc.Clear();
|
|
||||||
desc.SetShort(true);
|
|
||||||
desc.SetQuotes(true);
|
|
||||||
cond->Describe(&desc);
|
|
||||||
auto cond_val = zeek::make_intrusive<zeek::StringVal>(desc.Len(), (const char*)desc.Bytes());
|
|
||||||
|
|
||||||
zeek::StringValPtr msg_val = zeek::val_mgr->EmptyString();
|
zeek::StringValPtr msg_val = zeek::val_mgr->EmptyString();
|
||||||
|
|
||||||
if ( msg )
|
if ( msg )
|
||||||
{
|
{
|
||||||
// Eval() may fail if expression assumes assert
|
// Eval() may fail if expression assumes assert
|
||||||
|
@ -1904,50 +1905,22 @@ ValPtr AssertStmt::Exec(Frame* f, StmtFlowType& flow)
|
||||||
}
|
}
|
||||||
catch ( InterpreterException& e )
|
catch ( InterpreterException& e )
|
||||||
{
|
{
|
||||||
|
static ODesc desc;
|
||||||
desc.Clear();
|
desc.Clear();
|
||||||
|
desc.SetShort(true);
|
||||||
|
desc.SetQuotes(true);
|
||||||
desc.Add("<error eval ");
|
desc.Add("<error eval ");
|
||||||
msg->Describe(&desc);
|
msg->Describe(&desc);
|
||||||
desc.Add(">");
|
desc.Add(">");
|
||||||
msg_val = zeek::make_intrusive<zeek::StringVal>(desc.Len(), (const char*)desc.Bytes());
|
msg_val = zeek::make_intrusive<zeek::StringVal>(desc.Len(),
|
||||||
|
(const char*)desc.Bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorValPtr bt = nullptr;
|
report_assert(assert_result, cond_desc, msg_val, GetLocationInfo());
|
||||||
if ( run_result_hook || run_failure_hook )
|
|
||||||
{
|
|
||||||
bt = get_current_script_backtrace();
|
|
||||||
auto assert_elem = make_backtrace_element("assert", MakeEmptyCallArgumentVector(),
|
|
||||||
GetLocationInfo());
|
|
||||||
bt->Insert(0, std::move(assert_elem));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Breaking from either the assertion_failure() or assertion_result()
|
|
||||||
// hook can be used to suppress the default log message.
|
|
||||||
bool report_error = true;
|
|
||||||
|
|
||||||
if ( run_result_hook )
|
|
||||||
report_error &= assertion_result_hook
|
|
||||||
->Invoke(zeek::val_mgr->Bool(assert_result), cond_val, msg_val, bt)
|
|
||||||
->AsBool();
|
|
||||||
|
|
||||||
if ( assert_result )
|
|
||||||
return Val::nil;
|
return Val::nil;
|
||||||
|
|
||||||
if ( run_failure_hook )
|
|
||||||
report_error &= assertion_failure_hook->Invoke(cond_val, msg_val, bt)->AsBool();
|
|
||||||
|
|
||||||
if ( report_error )
|
|
||||||
{
|
|
||||||
std::string reporter_msg = util::fmt("assertion failure: %s", cond_val->CheckString());
|
|
||||||
if ( msg_val->Len() > 0 )
|
|
||||||
reporter_msg += util::fmt(" (%s)", msg_val->CheckString());
|
|
||||||
|
|
||||||
reporter->PushLocation(GetLocationInfo());
|
|
||||||
reporter->Error("%s", reporter_msg.c_str());
|
|
||||||
reporter->PopLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw InterpreterException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssertStmt::StmtDescribe(ODesc* d) const
|
void AssertStmt::StmtDescribe(ODesc* d) const
|
||||||
|
@ -1992,6 +1965,59 @@ TraversalCode AssertStmt::Traverse(TraversalCallback* cb) const
|
||||||
HANDLE_TC_STMT_POST(tc);
|
HANDLE_TC_STMT_POST(tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AssertException : public InterpreterException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AssertException() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
void report_assert(bool cond, std::string_view cond_desc, StringValPtr msg_val, const Location* loc)
|
||||||
|
{
|
||||||
|
static auto assertion_failure_hook = id::find_func("assertion_failure");
|
||||||
|
static auto assertion_result_hook = id::find_func("assertion_result");
|
||||||
|
|
||||||
|
bool run_result_hook = assertion_result_hook && assertion_result_hook->HasEnabledBodies();
|
||||||
|
bool run_failure_hook = assertion_failure_hook && assertion_failure_hook->HasEnabledBodies();
|
||||||
|
|
||||||
|
auto cond_val = zeek::make_intrusive<zeek::StringVal>(cond_desc);
|
||||||
|
|
||||||
|
VectorValPtr bt = nullptr;
|
||||||
|
if ( run_result_hook || run_failure_hook )
|
||||||
|
{
|
||||||
|
bt = get_current_script_backtrace();
|
||||||
|
auto assert_elem = make_backtrace_element("assert", MakeEmptyCallArgumentVector(), loc);
|
||||||
|
bt->Insert(0, std::move(assert_elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Breaking from either the assertion_failure() or assertion_result()
|
||||||
|
// hook can be used to suppress the default log message.
|
||||||
|
bool report_error = true;
|
||||||
|
|
||||||
|
if ( run_result_hook )
|
||||||
|
report_error &= assertion_result_hook
|
||||||
|
->Invoke(zeek::val_mgr->Bool(cond), cond_val, msg_val, bt)
|
||||||
|
->AsBool();
|
||||||
|
|
||||||
|
if ( cond )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( run_failure_hook )
|
||||||
|
report_error &= assertion_failure_hook->Invoke(cond_val, msg_val, bt)->AsBool();
|
||||||
|
|
||||||
|
if ( report_error )
|
||||||
|
{
|
||||||
|
std::string reporter_msg = util::fmt("assertion failure: %s", cond_val->CheckString());
|
||||||
|
if ( msg_val->Len() > 0 )
|
||||||
|
reporter_msg += util::fmt(" (%s)", msg_val->CheckString());
|
||||||
|
|
||||||
|
reporter->PushLocation(loc);
|
||||||
|
reporter->Error("%s", reporter_msg.c_str());
|
||||||
|
reporter->PopLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw AssertException();
|
||||||
|
}
|
||||||
|
|
||||||
WhenInfo::WhenInfo(ExprPtr arg_cond, FuncType::CaptureList* arg_cl, bool arg_is_return)
|
WhenInfo::WhenInfo(ExprPtr arg_cond, FuncType::CaptureList* arg_cl, bool arg_is_return)
|
||||||
: cond(std::move(arg_cond)), cl(arg_cl), is_return(arg_is_return)
|
: cond(std::move(arg_cond)), cl(arg_cl), is_return(arg_is_return)
|
||||||
{
|
{
|
||||||
|
|
12
src/Stmt.h
12
src/Stmt.h
|
@ -547,6 +547,10 @@ public:
|
||||||
|
|
||||||
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
|
ValPtr Exec(Frame* f, StmtFlowType& flow) override;
|
||||||
|
|
||||||
|
const auto& Cond() const { return cond; }
|
||||||
|
const auto& CondDesc() const { return cond_desc; }
|
||||||
|
const auto& Msg() const { return msg; }
|
||||||
|
|
||||||
void StmtDescribe(ODesc* d) const override;
|
void StmtDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
TraversalCode Traverse(TraversalCallback* cb) const override;
|
TraversalCode Traverse(TraversalCallback* cb) const override;
|
||||||
|
@ -559,9 +563,17 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExprPtr cond;
|
ExprPtr cond;
|
||||||
|
std::string cond_desc;
|
||||||
ExprPtr msg;
|
ExprPtr msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function for reporting on asserts that either failed, or should
|
||||||
|
// be processed regardless due to the presence of a "assertion_result" hook.
|
||||||
|
//
|
||||||
|
// If "cond" is false, throws an InterpreterException after reporting.
|
||||||
|
extern void report_assert(bool cond, std::string_view cond_desc, StringValPtr msg_val,
|
||||||
|
const Location* loc);
|
||||||
|
|
||||||
// A helper class for tracking all of the information associated with
|
// A helper class for tracking all of the information associated with
|
||||||
// a "when" statement, and constructing the necessary components in support
|
// a "when" statement, and constructing the necessary components in support
|
||||||
// of lambda-style captures.
|
// of lambda-style captures.
|
||||||
|
|
|
@ -720,6 +720,8 @@ private:
|
||||||
void GenForOverVector(const ExprPtr& tbl, const IDPtr& value_var, const IDPList* loop_vars);
|
void GenForOverVector(const ExprPtr& tbl, const IDPtr& value_var, const IDPList* loop_vars);
|
||||||
void GenForOverString(const ExprPtr& str, const IDPList* loop_vars);
|
void GenForOverString(const ExprPtr& str, const IDPList* loop_vars);
|
||||||
|
|
||||||
|
void GenAssertStmt(const AssertStmt* a);
|
||||||
|
|
||||||
// Nested level of loops/switches for which "break"'s should be
|
// Nested level of loops/switches for which "break"'s should be
|
||||||
// C++ breaks rather than a "hook" break.
|
// C++ breaks rather than a "hook" break.
|
||||||
int break_level = 0;
|
int break_level = 0;
|
||||||
|
|
|
@ -78,6 +78,10 @@ void CPPCompile::GenStmt(const Stmt* s)
|
||||||
GenForStmt(s->AsForStmt());
|
GenForStmt(s->AsForStmt());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case STMT_ASSERT:
|
||||||
|
GenAssertStmt(s->AsAssertStmt());
|
||||||
|
break;
|
||||||
|
|
||||||
case STMT_NEXT:
|
case STMT_NEXT:
|
||||||
Emit("continue;");
|
Emit("continue;");
|
||||||
break;
|
break;
|
||||||
|
@ -567,4 +571,33 @@ void CPPCompile::GenForOverString(const ExprPtr& str, const IDPList* loop_vars)
|
||||||
Emit("%s = std::move(sv__CPP);", IDName(lv0));
|
Emit("%s = std::move(sv__CPP);", IDName(lv0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPPCompile::GenAssertStmt(const AssertStmt* a)
|
||||||
|
{
|
||||||
|
auto& cond = a->Cond();
|
||||||
|
auto& msg = a->Msg();
|
||||||
|
|
||||||
|
Emit("{ // begin a new scope for internal \"assert\" variables");
|
||||||
|
Emit("static auto assertion_result_hook = id::find_func(\"assertion_result\");");
|
||||||
|
Emit("bool run_result_hook = assertion_result_hook && "
|
||||||
|
"assertion_result_hook->HasEnabledBodies();");
|
||||||
|
Emit("auto assert_result = %s;", GenExpr(cond, GEN_NATIVE));
|
||||||
|
Emit("if ( ! assert_result || run_result_hook )");
|
||||||
|
|
||||||
|
StartBlock();
|
||||||
|
if ( msg )
|
||||||
|
Emit("auto msg_val = %s;", GenExpr(msg, GEN_VAL_PTR));
|
||||||
|
else
|
||||||
|
Emit("auto msg_val = zeek::val_mgr->EmptyString();");
|
||||||
|
|
||||||
|
auto loc = a->GetLocationInfo();
|
||||||
|
Emit("static Location loc(\"%s\", %s, %s, %s, %s);", loc->filename,
|
||||||
|
std::to_string(loc->first_line), std::to_string(loc->last_line),
|
||||||
|
std::to_string(loc->first_column), std::to_string(loc->last_column));
|
||||||
|
Emit("report_assert(assert_result, \"%s\", msg_val, &loc);",
|
||||||
|
CPPEscape(a->CondDesc().c_str()).c_str());
|
||||||
|
EndBlock();
|
||||||
|
|
||||||
|
Emit("} // end of \"assert\" scope");
|
||||||
|
}
|
||||||
|
|
||||||
} // zeek::detail
|
} // zeek::detail
|
||||||
|
|
7
testing/btest/Baseline.cpp/language.assert-misc/out
Normal file
7
testing/btest/Baseline.cpp/language.assert-misc/out
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
f, lambda_<505728364269398358>
|
||||||
|
compiled-C++
|
||||||
|
g, lambda_<8496146571423528161>
|
||||||
|
compiled-C++
|
||||||
|
test_function, test_function
|
||||||
|
compiled-C++
|
Loading…
Add table
Add a link
Reference in a new issue