diff --git a/src/Expr.cc b/src/Expr.cc index dd514df74b..37e1770673 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -4026,7 +4026,27 @@ Val* RecordCoerceExpr::Fold(Val* v) const Type()->AsRecordType()->FieldDecl(i)->FindAttr(ATTR_DEFAULT); if ( def ) - val->Assign(i, def->AttrExpr()->Eval(0)); + { + Val* def_val = def->AttrExpr()->Eval(0); + BroType* def_type = def_val->Type(); + BroType* field_type = Type()->AsRecordType()->FieldType(i); + + if ( def_type->Tag() == TYPE_RECORD && + field_type->Tag() == TYPE_RECORD && + ! same_type(def_type, field_type) ) + { + Val* tmp = def_val->AsRecordVal()->CoerceTo( + field_type->AsRecordType()); + + if ( tmp ) + { + Unref(def_val); + def_val = tmp; + } + } + + val->Assign(i, def_val); + } else val->Assign(i, 0); } @@ -4297,6 +4317,10 @@ Val* ScheduleExpr::Eval(Frame* f) const if ( args ) { TimerMgr* tmgr = mgr.CurrentTimerMgr(); + + if ( ! tmgr ) + tmgr = timer_mgr; + tmgr->Add(new ScheduleTimer(event->Handler(), args, dt, tmgr)); } diff --git a/src/Val.cc b/src/Val.cc index 5133550236..dd86e71a9e 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2560,10 +2560,22 @@ RecordVal::RecordVal(RecordType* t) : MutableVal(t) Attributes* a = record_type->FieldDecl(i)->attrs; Attr* def_attr = a ? a->FindAttr(ATTR_DEFAULT) : 0; Val* def = def_attr ? def_attr->AttrExpr()->Eval(0) : 0; + BroType* type = record_type->FieldDecl(i)->type; + + if ( def && type->Tag() == TYPE_RECORD && + def->Type()->Tag() == TYPE_RECORD && + ! same_type(def->Type(), type) ) + { + Val* tmp = def->AsRecordVal()->CoerceTo(type->AsRecordType()); + if ( tmp ) + { + Unref(def); + def = tmp; + } + } if ( ! def && ! (a && a->FindAttr(ATTR_OPTIONAL)) ) { - BroType* type = record_type->FieldDecl(i)->type; TypeTag tag = type->Tag(); if ( tag == TYPE_RECORD ) diff --git a/src/bro.bif b/src/bro.bif index 4d0db54c8c..195e4c2bde 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -622,7 +622,7 @@ function md5_hmac%(...%): string ## ``md5_hash_update(c$http$md5_handle, some_more_data)`` in the ## :bro:id:`http_entity_data` event handler. When all data has arrived, a call ## to :bro:id:`md5_hash_finish` returns the final hash value. -## +## ## Returns: The opaque handle associated with this hash computation. ## ## .. bro:see:: md5_hmac md5_hash md5_hash_update md5_hash_finish @@ -2464,6 +2464,97 @@ function bytestring_to_double%(s: string%): double return new Val(ntohd(d), TYPE_DOUBLE); %} +## Converts a string of bytes to a :bro:type:`count`. +## +## s: A string of bytes containing the binary representation of the value. +## +## is_le: If true, *s* is assumed to be in little endian format, else it's big endian. +## +## Returns: The value contained in *s*, or 0 if the conversion failed. +## +function bytestring_to_count%(s: string, is_le: bool%): count + %{ +#ifdef HOST_BIGENDIAN + static const bool host_bigendian = true; +#else + static const bool host_bigendian = false; +#endif + const u_char *p = s->Bytes(); + unsigned int i; + + switch ( s->Len() ) { + case sizeof(uint8): + { + uint8 value = 0; + memcpy(&value, p, sizeof(uint8)); + return new Val(value, TYPE_COUNT); + } + + case sizeof(uint16): + { + uint16 value = 0; + + if ( (host_bigendian && is_le) || (! host_bigendian && ! is_le) ) + { + char buf[sizeof(uint16)]; + char *d = &buf[sizeof(uint16)-1]; + + for ( i = 0; i < sizeof(uint16); i++ ) + *d-- = *p++; + + memcpy(&value, buf, sizeof(uint16)); + } + else + memcpy(&value, p, sizeof(uint16)); + + return new Val(value, TYPE_COUNT); + } + + case sizeof(uint32): + { + uint32 value = 0; + + if ( (host_bigendian && is_le) || (! host_bigendian && ! is_le) ) + { + char buf[sizeof(uint32)]; + char *d = &buf[sizeof(uint32)-1]; + + for ( i = 0; i < sizeof(uint32); i++ ) + *d-- = *p++; + + memcpy(&value, buf, sizeof(uint32)); + } + else + memcpy(&value, p, sizeof(uint32)); + + return new Val(value, TYPE_COUNT); + } + + case sizeof(uint64): + { + uint64 value = 0; + + if ( (host_bigendian && is_le) || (! host_bigendian && ! is_le) ) + { + char buf[sizeof(uint64)]; + char *d = &buf[sizeof(uint64)-1]; + + for ( i = 0; i < sizeof(uint64); i++ ) + *d-- = *p++; + + memcpy(&value, buf, sizeof(uint64)); + } + else + memcpy(&value, p, sizeof(uint64)); + + return new Val(value, TYPE_COUNT); + } + } + + builtin_error("unsupported byte length for bytestring_to_count"); + return new Val(0, TYPE_COUNT); + %} + ## Converts a reverse pointer name to an address. For example, ## ``1.0.168.192.in-addr.arpa`` to ``192.168.0.1``. ## diff --git a/testing/btest/Baseline/bifs.bytestring_to_count/out b/testing/btest/Baseline/bifs.bytestring_to_count/out new file mode 100644 index 0000000000..e5f8c84f26 --- /dev/null +++ b/testing/btest/Baseline/bifs.bytestring_to_count/out @@ -0,0 +1,36 @@ +0 +0 +0 +0 +0 +0 +255 +255 +0 +0 +1000 +1000 +12345 +12345 +0 +0 +65535 +65535 +4294967295 +4294967295 +287454020 +1144201745 +255 +255 +2864429994 +2864429994 +0 +0 +18446744073709551615 +18446744073709551615 +18446742974214701055 +18446742974214701055 +65535 +65535 +0 +0 diff --git a/testing/btest/Baseline/language.event/out b/testing/btest/Baseline/language.event/out index d5a22b3745..41c3e0d717 100644 --- a/testing/btest/Baseline/language.event/out +++ b/testing/btest/Baseline/language.event/out @@ -1,4 +1,6 @@ event statement event part1 event part2 -schedule statement +schedule statement in bro_init +schedule statement in global +schedule statement another in bro_init diff --git a/testing/btest/Baseline/language.record-default-coercion/out b/testing/btest/Baseline/language.record-default-coercion/out index 2f0e6cd17d..bf76ba5033 100644 --- a/testing/btest/Baseline/language.record-default-coercion/out +++ b/testing/btest/Baseline/language.record-default-coercion/out @@ -1,3 +1,21 @@ +[bar=4321, foo=[foo=1234, quux=9876]] +[foo=1234, quux=9876] +9876 +[bar=4231, foo=[foo=1000, quux=9876]] +[foo=1000, quux=9876] +9876 +[bar=4321, foo=[foo=10, quux=42]] +[foo=10, quux=42] +42 +[bar=100, foo=[foo=1234, quux=9876]] +[foo=1234, quux=9876] +9876 +[bar=100, foo=[foo=1001, quux=9876]] +[foo=1001, quux=9876] +9876 +[bar=100, foo=[foo=11, quux=7]] +[foo=11, quux=7] +7 [a=13, c=13, v=[]] 0 [a=13, c=13, v=[test]] diff --git a/testing/btest/bifs/bytestring_to_count.bro b/testing/btest/bifs/bytestring_to_count.bro new file mode 100644 index 0000000000..e26b201f26 --- /dev/null +++ b/testing/btest/bifs/bytestring_to_count.bro @@ -0,0 +1,55 @@ + # +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + + +event bro_init() + { + + # unsupported byte lengths + print bytestring_to_count("", T); # 0 + print bytestring_to_count("", F); # 0 + print bytestring_to_count("\xAA\xBB\xCC", T); # 0 + print bytestring_to_count("\xAA\xBB\xCC", F); # 0 + print bytestring_to_count("\xAA\xBB\xCC\xDD\xEE", T); # 0 + print bytestring_to_count("\xAA\xBB\xCC\xDD\xEE", F); # 0 + + # 8 bit + print bytestring_to_count("\xff", T); # 255 + print bytestring_to_count("\xff", F); # 255 + print bytestring_to_count("\x00", T); # 0 + print bytestring_to_count("\x00", F); # 0 + + # 16 bit + print bytestring_to_count("\x03\xe8", F); # 1000 + print bytestring_to_count("\xe8\x03", T); # 1000 + print bytestring_to_count("\x30\x39", F); # 12345 + print bytestring_to_count("\x39\x30", T); # 12345 + print bytestring_to_count("\x00\x00", F); # 0 + print bytestring_to_count("\x00\x00", T); # 0 + + # 32 bit + print bytestring_to_count("\x00\x00\xff\xff", F); # 65535 + print bytestring_to_count("\xff\xff\x00\x00", T); # 65535 + print bytestring_to_count("\xff\xff\xff\xff", F); # 4294967295 + print bytestring_to_count("\xff\xff\xff\xff", T); # 4294967295 + print bytestring_to_count("\x11\x22\x33\x44", F); # 287454020 + print bytestring_to_count("\x11\x22\x33\x44", T); # 1144201745 + print bytestring_to_count("\x00\x00\x00\xff", F); # 255 + print bytestring_to_count("\xff\x00\x00\x00", T); # 255 + print bytestring_to_count("\xAA\xBB\xBB\xAA", F); # 2864429994 + print bytestring_to_count("\xAA\xBB\xBB\xAA", T); # 2864429994 + print bytestring_to_count("\x00\x00\x00\x00", F); # 0 + print bytestring_to_count("\x00\x00\x00\x00", T); # 0 + + # 64 bit + print bytestring_to_count("\xff\xff\xff\xff\xff\xff\xff\xff", F); # 18446744073709551615 + print bytestring_to_count("\xff\xff\xff\xff\xff\xff\xff\xff", T); # 18446744073709551615 + print bytestring_to_count("\xff\xff\xff\x00\x00\xff\xff\xff", F); # 18446742974214701055 + print bytestring_to_count("\xff\xff\xff\x00\x00\xff\xff\xff", T); # 18446742974214701055 + print bytestring_to_count("\x00\x00\x00\x00\x00\x00\xff\xff", F); # 65535 + print bytestring_to_count("\xff\xff\x00\x00\x00\x00\x00\x00", T); # 65535 + print bytestring_to_count("\x00\x00\x00\x00\x00\x00\x00\x00", T); # 0 + print bytestring_to_count("\x00\x00\x00\x00\x00\x00\x00\x00", F); # 0 + + } diff --git a/testing/btest/language/event.bro b/testing/btest/language/event.bro index e251a3e579..39a3e0da48 100644 --- a/testing/btest/language/event.bro +++ b/testing/btest/language/event.bro @@ -9,9 +9,9 @@ event e1() print "Error: this should not happen"; } -event e2() +event e2(s: string) { - print "schedule statement"; + print fmt("schedule statement %s", s); } event e3(test: string) @@ -36,7 +36,8 @@ event bro_init() event e1(); # Test calling an event with "schedule" statement - schedule 1 sec { e2() }; + schedule 1 sec { e2("in bro_init") }; + schedule 3 sec { e2("another in bro_init") }; # Test calling an event that has two separate definitions event e3("foo"); @@ -47,3 +48,5 @@ event bro_init() event e5(6); # TODO: this does not do anything } +# scheduling in outside of an event handler shouldn't crash. +schedule 2sec { e2("in global") }; diff --git a/testing/btest/language/record-default-coercion.bro b/testing/btest/language/record-default-coercion.bro index 7e717c39e2..822b845f65 100644 --- a/testing/btest/language/record-default-coercion.bro +++ b/testing/btest/language/record-default-coercion.bro @@ -7,12 +7,42 @@ type MyRecord: record { v: vector of string &default=vector(); }; -event bro_init() +type Foo: record { + foo: count; + quux: count &default=9876; +}; + +type Bar: record { + bar: count; + foo: Foo &default=[$foo=1234]; +}; + +function print_bar(b: Bar) { - local r: MyRecord = [$c=13]; - print r; - print |r$v|; - r$v[|r$v|] = "test"; - print r; - print |r$v|; + print b; + print b$foo; + print b$foo$quux; } + +global bar: Bar = [$bar=4321]; +global bar2: Bar = [$bar=4231, $foo=[$foo=1000]]; +global bar3: Bar = [$bar=4321, $foo=[$foo=10, $quux=42]]; + +print_bar(bar); +print_bar(bar2); +print_bar(bar3); + +local bar4: Bar = [$bar=100]; +local bar5: Bar = [$bar=100, $foo=[$foo=1001]]; +local bar6: Bar = [$bar=100, $foo=[$foo=11, $quux=7]]; + +print_bar(bar4); +print_bar(bar5); +print_bar(bar6); + +local r: MyRecord = [$c=13]; +print r; +print |r$v|; +r$v[|r$v|] = "test"; +print r; +print |r$v|;