Merge remote-tracking branch 'origin/topic/johanna/bit-1199'

* origin/topic/johanna/bit-1199:
  add a basic leak test for an unparseable enum
  Change the way the input framework deals with values it cannot convert into BroVals (especially enums)
  Make error message when encountering not existing enums better.

BIT-1199: #merged
This commit is contained in:
Robin Sommer 2015-03-23 10:25:43 -07:00
commit 88165ad72c
7 changed files with 310 additions and 135 deletions

View file

@ -971,7 +971,7 @@ Val* Manager::RecordValToIndexVal(RecordVal *r)
} }
Val* Manager::ValueToIndexVal(int num_fields, const RecordType *type, const Value* const *vals) Val* Manager::ValueToIndexVal(const Stream* i, int num_fields, const RecordType *type, const Value* const *vals, bool& have_error)
{ {
Val* idxval; Val* idxval;
int position = 0; int position = 0;
@ -979,7 +979,7 @@ Val* Manager::ValueToIndexVal(int num_fields, const RecordType *type, const Valu
if ( num_fields == 1 && type->FieldType(0)->Tag() != TYPE_RECORD ) if ( num_fields == 1 && type->FieldType(0)->Tag() != TYPE_RECORD )
{ {
idxval = ValueToVal(vals[0], type->FieldType(0)); idxval = ValueToVal(i, vals[0], type->FieldType(0), have_error);
position = 1; position = 1;
} }
else else
@ -988,11 +988,11 @@ Val* Manager::ValueToIndexVal(int num_fields, const RecordType *type, const Valu
for ( int j = 0 ; j < type->NumFields(); j++ ) for ( int j = 0 ; j < type->NumFields(); j++ )
{ {
if ( type->FieldType(j)->Tag() == TYPE_RECORD ) if ( type->FieldType(j)->Tag() == TYPE_RECORD )
l->Append(ValueToRecordVal(vals, l->Append(ValueToRecordVal(i, vals,
type->FieldType(j)->AsRecordType(), &position)); type->FieldType(j)->AsRecordType(), &position, have_error));
else else
{ {
l->Append(ValueToVal(vals[position], type->FieldType(j))); l->Append(ValueToVal(i, vals[position], type->FieldType(j), have_error));
position++; position++;
} }
} }
@ -1079,7 +1079,7 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
{ {
// seen before // seen before
if ( stream->num_val_fields == 0 || h->valhash == valhash ) if ( stream->num_val_fields == 0 || h->valhash == valhash )
{ {
// ok, exact duplicate, move entry to new dicrionary and do nothing else. // ok, exact duplicate, move entry to new dicrionary and do nothing else.
stream->lastDict->Remove(idxhash); stream->lastDict->Remove(idxhash);
stream->currDict->Insert(idxhash, h); stream->currDict->Insert(idxhash, h);
@ -1094,8 +1094,8 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
stream->lastDict->Remove(idxhash); stream->lastDict->Remove(idxhash);
// keep h for predicates // keep h for predicates
updated = true; updated = true;
} }
} }
Val* valval; Val* valval;
@ -1103,63 +1103,68 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
int position = stream->num_idx_fields; int position = stream->num_idx_fields;
bool convert_error = false; // this will be set to true by ValueTo* on Error
if ( stream->num_val_fields == 0 ) if ( stream->num_val_fields == 0 )
valval = 0; valval = 0;
else if ( stream->num_val_fields == 1 && !stream->want_record ) else if ( stream->num_val_fields == 1 && !stream->want_record )
valval = ValueToVal(vals[position], stream->rtype->FieldType(0)); valval = ValueToVal(i, vals[position], stream->rtype->FieldType(0), convert_error);
else else
valval = ValueToRecordVal(vals, stream->rtype, &position); valval = ValueToRecordVal(i, vals, stream->rtype, &position, convert_error);
// call stream first to determine if we really add / change the entry // call stream first to determine if we really add / change the entry
if ( stream->pred ) if ( stream->pred && ! convert_error )
{ {
EnumVal* ev; EnumVal* ev;
int startpos = 0; int startpos = 0;
predidx = ValueToRecordVal(vals, stream->itype, &startpos); bool pred_convert_error = false;
predidx = ValueToRecordVal(i, vals, stream->itype, &startpos, pred_convert_error);
if ( updated ) // if we encountered a convert error here - just continue as we would have without
ev = new EnumVal(BifEnum::Input::EVENT_CHANGED, BifType::Enum::Input::Event); // emitting the event. I do not really think that that can happen just here and not
else // at the top-level. But - this is safe.
ev = new EnumVal(BifEnum::Input::EVENT_NEW, BifType::Enum::Input::Event); if ( ! pred_convert_error )
bool result;
if ( stream->num_val_fields > 0 ) // we have values
result = CallPred(stream->pred, 3, ev, predidx->Ref(), valval->Ref());
else // no values
result = CallPred(stream->pred, 2, ev, predidx->Ref());
if ( result == false )
{ {
Unref(predidx); if ( updated )
Unref(valval); ev = new EnumVal(BifEnum::Input::EVENT_CHANGED, BifType::Enum::Input::Event);
if ( ! updated )
{
// just quit and delete everything we created.
delete idxhash;
return stream->num_val_fields + stream->num_idx_fields;
}
else else
ev = new EnumVal(BifEnum::Input::EVENT_NEW, BifType::Enum::Input::Event);
bool result;
if ( stream->num_val_fields > 0 ) // we have values
result = CallPred(stream->pred, 3, ev, predidx->Ref(), valval->Ref());
else // no values
result = CallPred(stream->pred, 2, ev, predidx->Ref());
if ( result == false )
{ {
// keep old one Unref(predidx);
stream->currDict->Insert(idxhash, h); Unref(valval);
delete idxhash;
return stream->num_val_fields + stream->num_idx_fields; if ( ! updated )
{
// just quit and delete everything we created.
delete idxhash;
return stream->num_val_fields + stream->num_idx_fields;
}
else
{
// keep old one
stream->currDict->Insert(idxhash, h);
delete idxhash;
return stream->num_val_fields + stream->num_idx_fields;
}
} }
} }
} }
// now we don't need h anymore - if we are here, the entry is updated and a new h is created. // now we don't need h anymore - if we are here, the entry is updated and a new h is created.
if ( h ) delete h;
{ h = 0;
delete h;
h = 0;
}
Val* idxval; Val* idxval;
if ( predidx != 0 ) if ( predidx != 0 )
@ -1168,7 +1173,20 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
// I think there is an unref missing here. But if I insert is, it crashes :) // I think there is an unref missing here. But if I insert is, it crashes :)
} }
else else
idxval = ValueToIndexVal(stream->num_idx_fields, stream->itype, vals); idxval = ValueToIndexVal(i, stream->num_idx_fields, stream->itype, vals, convert_error);
if ( convert_error )
{
// abort here and free everything that was allocated so far.
Unref(predidx);
Unref(valval);
Unref(idxval);
delete idxhash;
return stream->num_val_fields + stream->num_idx_fields;
}
assert(idxval);
Val* oldval = 0; Val* oldval = 0;
if ( updated == true ) if ( updated == true )
@ -1178,7 +1196,6 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
oldval = stream->tab->Lookup(idxval, false); oldval = stream->tab->Lookup(idxval, false);
} }
assert(idxval);
HashKey* k = stream->tab->ComputeHash(idxval); HashKey* k = stream->tab->ComputeHash(idxval);
if ( ! k ) if ( ! k )
reporter->InternalError("could not hash"); reporter->InternalError("could not hash");
@ -1203,16 +1220,21 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
{ {
EnumVal* ev; EnumVal* ev;
int startpos = 0; int startpos = 0;
Val* predidx = ValueToRecordVal(vals, stream->itype, &startpos); Val* predidx = ValueToRecordVal(i, vals, stream->itype, &startpos, convert_error);
if ( updated ) if ( convert_error )
{
// the only thing to clean up here is predidx. Everything else should
// already be ok again
Unref(predidx);
}
else if ( updated )
{ // in case of update send back the old value. { // in case of update send back the old value.
assert ( stream->num_val_fields > 0 ); assert ( stream->num_val_fields > 0 );
ev = new EnumVal(BifEnum::Input::EVENT_CHANGED, BifType::Enum::Input::Event); ev = new EnumVal(BifEnum::Input::EVENT_CHANGED, BifType::Enum::Input::Event);
assert ( oldval != 0 ); assert ( oldval != 0 );
SendEvent(stream->event, 4, stream->description->Ref(), ev, predidx, oldval); SendEvent(stream->event, 4, stream->description->Ref(), ev, predidx, oldval);
} }
else else
{ {
ev = new EnumVal(BifEnum::Input::EVENT_NEW, BifType::Enum::Input::Event); ev = new EnumVal(BifEnum::Input::EVENT_NEW, BifType::Enum::Input::Event);
@ -1223,7 +1245,6 @@ int Manager::SendEntryTable(Stream* i, const Value* const *vals)
} }
else else
SendEvent(stream->event, 4, stream->description->Ref(), ev, predidx, valval->Ref()); SendEvent(stream->event, 4, stream->description->Ref(), ev, predidx, valval->Ref());
} }
} }
@ -1416,7 +1437,6 @@ int Manager::SendEventStreamEvent(Stream* i, EnumVal* type, const Value* const *
assert(i->stream_type == EVENT_STREAM); assert(i->stream_type == EVENT_STREAM);
EventStream* stream = (EventStream*) i; EventStream* stream = (EventStream*) i;
Val *val;
list<Val*> out_vals; list<Val*> out_vals;
Ref(stream->description); Ref(stream->description);
out_vals.push_back(stream->description); out_vals.push_back(stream->description);
@ -1425,9 +1445,11 @@ int Manager::SendEventStreamEvent(Stream* i, EnumVal* type, const Value* const *
int position = 0; int position = 0;
bool convert_error = false;
if ( stream->want_record ) if ( stream->want_record )
{ {
RecordVal * r = ValueToRecordVal(vals, stream->fields, &position); RecordVal * r = ValueToRecordVal(i, vals, stream->fields, &position, convert_error);
out_vals.push_back(r); out_vals.push_back(r);
} }
@ -1438,13 +1460,13 @@ int Manager::SendEventStreamEvent(Stream* i, EnumVal* type, const Value* const *
Val* val = 0; Val* val = 0;
if ( stream->fields->FieldType(j)->Tag() == TYPE_RECORD ) if ( stream->fields->FieldType(j)->Tag() == TYPE_RECORD )
val = ValueToRecordVal(vals, val = ValueToRecordVal(i, vals,
stream->fields->FieldType(j)->AsRecordType(), stream->fields->FieldType(j)->AsRecordType(),
&position); &position, convert_error);
else else
{ {
val = ValueToVal(vals[position], stream->fields->FieldType(j)); val = ValueToVal(i, vals[position], stream->fields->FieldType(j), convert_error);
position++; position++;
} }
@ -1452,7 +1474,14 @@ int Manager::SendEventStreamEvent(Stream* i, EnumVal* type, const Value* const *
} }
} }
SendEvent(stream->event, out_vals); if ( convert_error )
{
// we have an error somewhere in our out_vals. Just delete all of them.
for ( list<Val*>::const_iterator it = out_vals.begin(), end = out_vals.end(); it != end; ++it )
Unref(*it);
}
else
SendEvent(stream->event, out_vals);
return stream->num_fields; return stream->num_fields;
} }
@ -1464,7 +1493,9 @@ int Manager::PutTable(Stream* i, const Value* const *vals)
assert(i->stream_type == TABLE_STREAM); assert(i->stream_type == TABLE_STREAM);
TableStream* stream = (TableStream*) i; TableStream* stream = (TableStream*) i;
Val* idxval = ValueToIndexVal(stream->num_idx_fields, stream->itype, vals); bool convert_error = 0;
Val* idxval = ValueToIndexVal(i, stream->num_idx_fields, stream->itype, vals, convert_error);
Val* valval; Val* valval;
int position = stream->num_idx_fields; int position = stream->num_idx_fields;
@ -1473,9 +1504,16 @@ int Manager::PutTable(Stream* i, const Value* const *vals)
valval = 0; valval = 0;
else if ( stream->num_val_fields == 1 && stream->want_record == 0 ) else if ( stream->num_val_fields == 1 && stream->want_record == 0 )
valval = ValueToVal(vals[position], stream->rtype->FieldType(0)); valval = ValueToVal(i, vals[position], stream->rtype->FieldType(0), convert_error);
else else
valval = ValueToRecordVal(vals, stream->rtype, &position); valval = ValueToRecordVal(i, vals, stream->rtype, &position, convert_error);
if ( convert_error )
{
Unref(valval);
Unref(idxval);
return stream->num_idx_fields + stream->num_val_fields;
}
// if we have a subscribed event, we need to figure out, if this is an update or not // if we have a subscribed event, we need to figure out, if this is an update or not
// same for predicates // same for predicates
@ -1503,31 +1541,37 @@ int Manager::PutTable(Stream* i, const Value* const *vals)
{ {
EnumVal* ev; EnumVal* ev;
int startpos = 0; int startpos = 0;
Val* predidx = ValueToRecordVal(vals, stream->itype, &startpos); bool pred_convert_error = false;
Val* predidx = ValueToRecordVal(i, vals, stream->itype, &startpos, pred_convert_error);
if ( updated ) if ( pred_convert_error )
ev = new EnumVal(BifEnum::Input::EVENT_CHANGED, Unref(predidx);
BifType::Enum::Input::Event);
else else
ev = new EnumVal(BifEnum::Input::EVENT_NEW,
BifType::Enum::Input::Event);
bool result;
if ( stream->num_val_fields > 0 ) // we have values
{ {
Ref(valval); if ( updated )
result = CallPred(stream->pred, 3, ev, predidx, valval); ev = new EnumVal(BifEnum::Input::EVENT_CHANGED,
} BifType::Enum::Input::Event);
else // no values else
result = CallPred(stream->pred, 2, ev, predidx); ev = new EnumVal(BifEnum::Input::EVENT_NEW,
BifType::Enum::Input::Event);
if ( result == false ) bool result;
{ if ( stream->num_val_fields > 0 ) // we have values
// do nothing {
Unref(idxval); Ref(valval);
Unref(valval); result = CallPred(stream->pred, 3, ev, predidx, valval);
Unref(oldval); }
return stream->num_val_fields + stream->num_idx_fields; else // no values
result = CallPred(stream->pred, 2, ev, predidx);
if ( result == false )
{
// do nothing
Unref(idxval);
Unref(valval);
Unref(oldval);
return stream->num_val_fields + stream->num_idx_fields;
}
} }
} }
@ -1538,28 +1582,34 @@ int Manager::PutTable(Stream* i, const Value* const *vals)
{ {
EnumVal* ev; EnumVal* ev;
int startpos = 0; int startpos = 0;
Val* predidx = ValueToRecordVal(vals, stream->itype, &startpos); bool event_convert_error = false;
Val* predidx = ValueToRecordVal(i, vals, stream->itype, &startpos, event_convert_error);
if ( updated ) if ( event_convert_error )
{ Unref(predidx);
// in case of update send back the old value.
assert ( stream->num_val_fields > 0 );
ev = new EnumVal(BifEnum::Input::EVENT_CHANGED,
BifType::Enum::Input::Event);
assert ( oldval != 0 );
SendEvent(stream->event, 4, stream->description->Ref(),
ev, predidx, oldval);
}
else else
{ {
ev = new EnumVal(BifEnum::Input::EVENT_NEW, if ( updated )
BifType::Enum::Input::Event); {
if ( stream->num_val_fields == 0 ) // in case of update send back the old value.
assert ( stream->num_val_fields > 0 );
ev = new EnumVal(BifEnum::Input::EVENT_CHANGED,
BifType::Enum::Input::Event);
assert ( oldval != 0 );
SendEvent(stream->event, 4, stream->description->Ref(), SendEvent(stream->event, 4, stream->description->Ref(),
ev, predidx); ev, predidx, oldval);
}
else else
SendEvent(stream->event, 4, stream->description->Ref(), {
ev, predidx, valval->Ref()); ev = new EnumVal(BifEnum::Input::EVENT_NEW,
BifType::Enum::Input::Event);
if ( stream->num_val_fields == 0 )
SendEvent(stream->event, 4, stream->description->Ref(),
ev, predidx);
else
SendEvent(stream->event, 4, stream->description->Ref(),
ev, predidx, valval->Ref());
}
} }
} }
@ -1612,29 +1662,42 @@ bool Manager::Delete(ReaderFrontend* reader, Value* *vals)
if ( i->stream_type == TABLE_STREAM ) if ( i->stream_type == TABLE_STREAM )
{ {
TableStream* stream = (TableStream*) i; TableStream* stream = (TableStream*) i;
Val* idxval = ValueToIndexVal(stream->num_idx_fields, stream->itype, vals); bool convert_error = false;
Val* idxval = ValueToIndexVal(i, stream->num_idx_fields, stream->itype, vals, convert_error);
assert(idxval != 0); assert(idxval != 0);
readVals = stream->num_idx_fields + stream->num_val_fields; readVals = stream->num_idx_fields + stream->num_val_fields;
bool streamresult = true; bool streamresult = true;
if ( convert_error )
{
Unref(idxval);
return false;
}
if ( stream->pred || stream->event ) if ( stream->pred || stream->event )
{ {
Val *val = stream->tab->Lookup(idxval); Val *val = stream->tab->Lookup(idxval);
if ( stream->pred ) if ( stream->pred )
{ {
Ref(val);
EnumVal *ev = new EnumVal(BifEnum::Input::EVENT_REMOVED, BifType::Enum::Input::Event);
int startpos = 0; int startpos = 0;
Val* predidx = ValueToRecordVal(vals, stream->itype, &startpos); Val* predidx = ValueToRecordVal(i, vals, stream->itype, &startpos, convert_error);
streamresult = CallPred(stream->pred, 3, ev, predidx, val); if ( convert_error )
Unref(predidx);
if ( streamresult == false ) else
{ {
// keep it. Ref(val);
Unref(idxval); EnumVal *ev = new EnumVal(BifEnum::Input::EVENT_REMOVED, BifType::Enum::Input::Event);
success = true;
streamresult = CallPred(stream->pred, 3, ev, predidx, val);
if ( streamresult == false )
{
// keep it.
Unref(idxval);
success = true;
}
} }
} }
@ -1708,8 +1771,15 @@ bool Manager::CallPred(Func* pred_func, const int numvals, ...)
return result; return result;
} }
bool Manager::SendEvent(const string& name, const int num_vals, Value* *vals) bool Manager::SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, Value* *vals)
{ {
Stream *i = FindStream(reader);
if ( i == 0 )
{
reporter->InternalWarning("Unknown reader %s in SendEvent for event %s", reader->Name(), name.c_str());
return false;
}
EventHandler* handler = event_registry->Lookup(name.c_str()); EventHandler* handler = event_registry->Lookup(name.c_str());
if ( handler == 0 ) if ( handler == 0 )
{ {
@ -1732,13 +1802,22 @@ bool Manager::SendEvent(const string& name, const int num_vals, Value* *vals)
return false; return false;
} }
val_list* vl = new val_list; bool convert_error = false;
for ( int i = 0; i < num_vals; i++)
vl->append(ValueToVal(vals[i], type->FieldType(i)));
mgr.QueueEvent(handler, vl, SOURCE_LOCAL); val_list* vl = new val_list;
for ( int j = 0; j < num_vals; j++)
vl->append(ValueToVal(i, vals[j], type->FieldType(j), convert_error));
delete_value_ptr_array(vals, num_vals); delete_value_ptr_array(vals, num_vals);
if ( convert_error )
{
delete_vals(vl);
return false;
}
else
mgr.QueueEvent(handler, vl, SOURCE_LOCAL);
return true; return true;
} }
@ -1809,8 +1888,8 @@ RecordVal* Manager::ListValToRecordVal(ListVal* list, RecordType *request_type,
} }
// Convert a threading value to a record value // Convert a threading value to a record value
RecordVal* Manager::ValueToRecordVal(const Value* const *vals, RecordVal* Manager::ValueToRecordVal(const Stream* stream, const Value* const *vals,
RecordType *request_type, int* position) RecordType *request_type, int* position, bool& have_error)
{ {
assert(position != 0); // we need the pointer to point to data. assert(position != 0); // we need the pointer to point to data.
@ -1819,7 +1898,7 @@ RecordVal* Manager::ValueToRecordVal(const Value* const *vals,
{ {
Val* fieldVal = 0; Val* fieldVal = 0;
if ( request_type->FieldType(i)->Tag() == TYPE_RECORD ) if ( request_type->FieldType(i)->Tag() == TYPE_RECORD )
fieldVal = ValueToRecordVal(vals, request_type->FieldType(i)->AsRecordType(), position); fieldVal = ValueToRecordVal(stream, vals, request_type->FieldType(i)->AsRecordType(), position, have_error);
else if ( request_type->FieldType(i)->Tag() == TYPE_FILE || else if ( request_type->FieldType(i)->Tag() == TYPE_FILE ||
request_type->FieldType(i)->Tag() == TYPE_FUNC ) request_type->FieldType(i)->Tag() == TYPE_FUNC )
{ {
@ -1834,7 +1913,7 @@ RecordVal* Manager::ValueToRecordVal(const Value* const *vals,
} }
else else
{ {
fieldVal = ValueToVal(vals[*position], request_type->FieldType(i)); fieldVal = ValueToVal(stream, vals[*position], request_type->FieldType(i), have_error);
(*position)++; (*position)++;
} }
@ -2103,12 +2182,17 @@ HashKey* Manager::HashValues(const int num_elements, const Value* const *vals)
} }
// convert threading value to Bro value // convert threading value to Bro value
Val* Manager::ValueToVal(const Value* val, BroType* request_type) // have_error is a reference to a boolean which is set to true as soon as an error occured.
// When have_error is set to true at the beginning of the function, it is assumed that
// an error already occured in the past and processing is aborted.
Val* Manager::ValueToVal(const Stream* i, const Value* val, BroType* request_type, bool& have_error)
{ {
if ( have_error )
return 0;
if ( request_type->Tag() != TYPE_ANY && request_type->Tag() != val->type ) if ( request_type->Tag() != TYPE_ANY && request_type->Tag() != val->type )
{ {
reporter->InternalError("Typetags don't match: %d vs %d", request_type->Tag(), val->type); reporter->InternalError("Typetags don't match: %d vs %d in stream %s", request_type->Tag(), val->type, i->name.c_str());
return 0; return 0;
} }
@ -2189,11 +2273,12 @@ Val* Manager::ValueToVal(const Value* val, BroType* request_type)
set_index->Append(type->Ref()); set_index->Append(type->Ref());
SetType* s = new SetType(set_index, 0); SetType* s = new SetType(set_index, 0);
TableVal* t = new TableVal(s); TableVal* t = new TableVal(s);
for ( int i = 0; i < val->val.set_val.size; i++ ) for ( int j = 0; j < val->val.set_val.size; j++ )
{ {
Val* assignval = ValueToVal( val->val.set_val.vals[i], type ); Val* assignval = ValueToVal(i, val->val.set_val.vals[j], type, have_error);
t->Assign(assignval, 0); t->Assign(assignval, 0);
Unref(assignval); // idex is not consumed by assign. Unref(assignval); // index is not consumed by assign.
} }
Unref(s); Unref(s);
@ -2206,8 +2291,10 @@ Val* Manager::ValueToVal(const Value* val, BroType* request_type)
BroType* type = request_type->AsVectorType()->YieldType(); BroType* type = request_type->AsVectorType()->YieldType();
VectorType* vt = new VectorType(type->Ref()); VectorType* vt = new VectorType(type->Ref());
VectorVal* v = new VectorVal(vt); VectorVal* v = new VectorVal(vt);
for ( int i = 0; i < val->val.vector_val.size; i++ ) for ( int j = 0; j < val->val.vector_val.size; j++ )
v->Assign(i, ValueToVal( val->val.set_val.vals[i], type )); {
v->Assign(j, ValueToVal(i, val->val.set_val.vals[j], type, have_error));
}
Unref(vt); Unref(vt);
return v; return v;
@ -2216,25 +2303,29 @@ Val* Manager::ValueToVal(const Value* val, BroType* request_type)
case TYPE_ENUM: { case TYPE_ENUM: {
// Convert to string first to not have to deal with missing // Convert to string first to not have to deal with missing
// \0's... // \0's...
string module_string(val->val.string_val.data, val->val.string_val.length); string enum_string(val->val.string_val.data, val->val.string_val.length);
string var_string(val->val.string_val.data, val->val.string_val.length);
string module = extract_module_name(module_string.c_str()); string module = extract_module_name(enum_string.c_str());
string var = extract_var_name(var_string.c_str()); string var = extract_var_name(enum_string.c_str());
// Well, this is kind of stupid, because EnumType just // Well, this is kind of stupid, because EnumType just
// mangles the module name and the var name together again... // mangles the module name and the var name together again...
// but well. // but well.
bro_int_t index = request_type->AsEnumType()->Lookup(module, var.c_str()); bro_int_t index = request_type->AsEnumType()->Lookup(module, var.c_str());
if ( index == -1 ) if ( index == -1 )
reporter->InternalError("Value not found in enum mappimg. Module: %s, var: %s, var size: %zu", {
module.c_str(), var.c_str(), var.size()); reporter->Error("Value not '%s' for stream '%s' is not a valid enum.",
enum_string.c_str(), i->name.c_str());
have_error = true;
return 0;
}
return new EnumVal(index, request_type->Ref()->AsEnumType()); return new EnumVal(index, request_type->Ref()->AsEnumType());
} }
default: default:
reporter->InternalError("unsupported type for input_read"); reporter->InternalError("Unsupported type for input_read in stream %s", i->name.c_str());
} }
assert(false); assert(false);

View file

@ -129,7 +129,7 @@ protected:
// Allows readers to directly send Bro events. The num_vals and vals // Allows readers to directly send Bro events. The num_vals and vals
// must be the same the named event expects. Takes ownership of // must be the same the named event expects. Takes ownership of
// threading::Value fields. // threading::Value fields.
bool SendEvent(const string& name, const int num_vals, threading::Value* *vals); bool SendEvent(ReaderFrontend* reader, const string& name, const int num_vals, threading::Value* *vals);
// Instantiates a new ReaderBackend of the given type (note that // Instantiates a new ReaderBackend of the given type (note that
// doing so creates a new thread!). // doing so creates a new thread!).
@ -205,14 +205,14 @@ private:
// Convert Threading::Value to an internal Bro Type (works also with // Convert Threading::Value to an internal Bro Type (works also with
// Records). // Records).
Val* ValueToVal(const threading::Value* val, BroType* request_type); Val* ValueToVal(const Stream* i, const threading::Value* val, BroType* request_type, bool& have_error);
// Convert Threading::Value to an internal Bro List type. // Convert Threading::Value to an internal Bro List type.
Val* ValueToIndexVal(int num_fields, const RecordType* type, const threading::Value* const *vals); Val* ValueToIndexVal(const Stream* i, int num_fields, const RecordType* type, const threading::Value* const *vals, bool& have_error);
// Converts a threading::value to a record type. Mostly used by // Converts a threading::value to a record type. Mostly used by
// ValueToVal. // ValueToVal.
RecordVal* ValueToRecordVal(const threading::Value* const *vals, RecordType *request_type, int* position); RecordVal* ValueToRecordVal(const Stream* i, const threading::Value* const *vals, RecordType *request_type, int* position, bool& have_error);
Val* RecordValToIndexVal(RecordVal *r); Val* RecordValToIndexVal(RecordVal *r);

View file

@ -64,7 +64,7 @@ public:
virtual bool Process() virtual bool Process()
{ {
bool success = input_mgr->SendEvent(name, num_vals, val); bool success = input_mgr->SendEvent(Object(), name, num_vals, val);
if ( ! success ) if ( ! success )
reporter->Error("SendEvent for event %s failed", name); reporter->Error("SendEvent for event %s failed", name);

View file

@ -0,0 +1,2 @@
error: Value not 'IdoNot::Exist' for stream 'enum' is not a valid enum.
received termination signal

View file

@ -0,0 +1,4 @@
Table:
{
}

View file

@ -0,0 +1,41 @@
# Needs perftools support.
#
# @TEST-GROUP: leaks
#
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
#
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local btest-bg-run bro bro -m -b %INPUT
# @TEST-EXEC: btest-bg-wait 15
@TEST-START-FILE input.log
#fields e i
IdoNot::Exist 1
@TEST-END-FILE
redef exit_only_after_terminate = T;
module A;
type Idx: record {
i: int;
};
type Val: record {
e: Log::ID;
};
global etable: table[int] of Log::ID = table();
event bro_init()
{
# first read in the old stuff into the table...
Input::add_table([$source="../input.log", $name="enum", $idx=Idx, $val=Val, $destination=etable, $want_record=F]);
}
event Input::end_of_data(name: string, source:string)
{
print "Table:";
print etable;
Input::remove("enum");
terminate();
}

View file

@ -0,0 +1,37 @@
# @TEST-EXEC: btest-bg-run bro bro -b %INPUT
# @TEST-EXEC: btest-bg-wait 10
# @TEST-EXEC: btest-diff bro/.stderr
# @TEST-EXEC: btest-diff bro/.stdout
@TEST-START-FILE input.log
#fields e i
IdoNot::Exist 1
@TEST-END-FILE
redef exit_only_after_terminate = T;
module A;
type Idx: record {
i: int;
};
type Val: record {
e: Log::ID;
};
global etable: table[int] of Log::ID = table();
event bro_init()
{
# first read in the old stuff into the table...
Input::add_table([$source="../input.log", $name="enum", $idx=Idx, $val=Val, $destination=etable, $want_record=F]);
}
event Input::end_of_data(name: string, source:string)
{
print "Table:";
print etable;
Input::remove("enum");
terminate();
}