Experimental code to better handle interpreter errors.

Currently, a lot of interpreter runtime errors, such as an access to
an unset optional record field, cause Bro to abort with an internal
error. This is an experimental branch that turns such errors into
non-fatal runtime errors by internally raising exceptions. These are
caught upstream and processing continues afterwards.

For now, not many errors actually raise exceptions (the example above
does though). We'll need to go through them eventually and adapt the
current Internal() calls (and potentially others). More generally, at
some point we should cleanup the interpreter error handling (unifying
errors reported at parse- and runtime; and switching to exceptions for
all Expr/Stmt/Vals). But that's a larger change and left for later.

The main question for now is if this code is already helpful enough to
go into 2.0. It will quite likely prevent a number of crashes due to
script errors.
This commit is contained in:
Robin Sommer 2011-10-09 20:28:06 -07:00
parent 0ec1fa6a53
commit 15ab287436
12 changed files with 213 additions and 38 deletions

View file

@ -39,7 +39,7 @@ void Reporter::Info(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
DoLog("", reporter_info, stderr, 0, 0, true, true, fmt, ap);
DoLog("", reporter_info, stderr, 0, 0, true, true, 0, fmt, ap);
va_end(ap);
}
@ -47,7 +47,7 @@ void Reporter::Warning(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
DoLog("warning", reporter_warning, stderr, 0, 0, true, true, fmt, ap);
DoLog("warning", reporter_warning, stderr, 0, 0, true, true, 0, fmt, ap);
va_end(ap);
}
@ -56,7 +56,7 @@ void Reporter::Error(const char* fmt, ...)
++errors;
va_list ap;
va_start(ap, fmt);
DoLog("error", reporter_error, stderr, 0, 0, true, true, fmt, ap);
DoLog("error", reporter_error, stderr, 0, 0, true, true, 0, fmt, ap);
va_end(ap);
}
@ -66,7 +66,7 @@ void Reporter::FatalError(const char* fmt, ...)
va_start(ap, fmt);
// Always log to stderr.
DoLog("fatal error", 0, stderr, 0, 0, true, false, fmt, ap);
DoLog("fatal error", 0, stderr, 0, 0, true, false, 0, fmt, ap);
va_end(ap);
@ -80,7 +80,7 @@ void Reporter::FatalErrorWithCore(const char* fmt, ...)
va_start(ap, fmt);
// Always log to stderr.
DoLog("fatal error", 0, stderr, 0, 0, true, false, fmt, ap);
DoLog("fatal error", 0, stderr, 0, 0, true, false, 0, fmt, ap);
va_end(ap);
@ -88,13 +88,29 @@ void Reporter::FatalErrorWithCore(const char* fmt, ...)
abort();
}
void Reporter::ExprRuntimeError(const Expr* expr, const char* fmt, ...)
{
++errors;
ODesc d;
expr->Describe(&d);
PushLocation(expr->GetLocationInfo());
va_list ap;
va_start(ap, fmt);
DoLog("expression error", reporter_error, stderr, 0, 0, true, true, d.Description(), fmt, ap);
va_end(ap);
PopLocation();
throw InterpreterException();
}
void Reporter::InternalError(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
// Always log to stderr.
DoLog("internal error", 0, stderr, 0, 0, true, false, fmt, ap);
DoLog("internal error", 0, stderr, 0, 0, true, false, 0, fmt, ap);
va_end(ap);
@ -106,7 +122,7 @@ void Reporter::InternalWarning(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
DoLog("internal warning", reporter_warning, stderr, 0, 0, true, true, fmt, ap);
DoLog("internal warning", reporter_warning, stderr, 0, 0, true, true, 0, fmt, ap);
va_end(ap);
}
@ -133,7 +149,7 @@ void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* add
va_list ap;
va_start(ap, fmt_name);
DoLog("weird", event, stderr, 0, vl, false, false, fmt_name, ap);
DoLog("weird", event, stderr, 0, vl, false, false, 0, fmt_name, ap);
va_end(ap);
delete vl;
@ -147,7 +163,7 @@ void Reporter::WeirdFlowHelper(const uint32* orig, const uint32* resp, const cha
va_list ap;
va_start(ap, fmt_name);
DoLog("weird", flow_weird, stderr, 0, vl, false, false, fmt_name, ap);
DoLog("weird", flow_weird, stderr, 0, vl, false, false, 0, fmt_name, ap);
va_end(ap);
delete vl;
@ -173,7 +189,7 @@ void Reporter::Weird(const uint32* orig, const uint32* resp, const char* name)
WeirdFlowHelper(orig, resp, "%s", name);
}
void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Connection* conn, val_list* addl, bool location, bool time, const char* fmt, va_list ap)
void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Connection* conn, val_list* addl, bool location, bool time, const char* postfix, const char* fmt, va_list ap)
{
static char tmp[512];
@ -235,6 +251,9 @@ void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Conne
int n = vsnprintf(buffer, size, fmt, aq);
va_end(aq);
if ( postfix )
n += strlen(postfix) + 10; // Add a bit of slack.
if ( n > -1 && n < size )
// We had enough space;
break;
@ -247,6 +266,11 @@ void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Conne
FatalError("out of memory in Reporter");
}
if ( postfix )
// Note, if you change this fmt string, adjust the additional
// buffer size above.
sprintf(buffer + strlen(buffer), " [%s]", postfix);
if ( event && via_events && ! in_error_handler )
{
val_list* vl = new val_list;