From f7e07f5f097036bf80252b03e5e79408f3f243be Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 29 Nov 2012 15:44:03 -0600 Subject: [PATCH] Fix various bugs with table/set attributes. - Identifiers that are initialized with set()/table() constructor expressions now inherit attributes from the expression. Before, statements like const i: set[string] = set() &redef; associated the attribute with the set() constructor, but not the "i" identifier, preventing redefinition. Addresses #866. - Allow &default attribute to apply to tables initialized as empty (via either "{ }" or "table()") or if the expression supplied to it can evaluate to a type that's promotable to the same yield type as the table. --- src/Attr.cc | 10 ++ src/Expr.cc | 2 +- src/Expr.h | 4 + src/Var.cc | 28 +++++ .../Baseline/language.table-init-attrs/output | 91 ++++++++++++++ testing/btest/language/table-init-attrs.bro | 115 ++++++++++++++++++ 6 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/language.table-init-attrs/output create mode 100644 testing/btest/language/table-init-attrs.bro diff --git a/src/Attr.cc b/src/Attr.cc index 6e0769c7b0..6cc582f053 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -260,6 +260,11 @@ void Attributes::CheckAttr(Attr* a) // Ok. break; + if ( type->Tag() == TYPE_TABLE && + type->AsTableType()->IsUnspecifiedTable() ) + // Ok. + break; + a->AttrExpr()->Error("&default value has inconsistent type", type); } @@ -290,6 +295,11 @@ void Attributes::CheckAttr(Attr* a) // Ok. break; + Expr* e = a->AttrExpr(); + if ( check_and_promote_expr(e, ytype) ) + // Ok. + break; + Error("&default value has inconsistent type 2"); } diff --git a/src/Expr.cc b/src/Expr.cc index 89680b9b5b..5b472ab6a6 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3445,7 +3445,7 @@ Val* SetConstructorExpr::Eval(Frame* f) const if ( IsError() ) return 0; - TableVal* aggr = new TableVal(type->AsTableType(), 0); + TableVal* aggr = new TableVal(type->AsTableType(), attrs); const expr_list& exprs = op->AsListExpr()->Exprs(); loop_over_list(exprs, i) diff --git a/src/Expr.h b/src/Expr.h index bd4824f8ee..afdf02c124 100644 --- a/src/Expr.h +++ b/src/Expr.h @@ -747,6 +747,8 @@ public: TableConstructorExpr(ListExpr* constructor_list, attr_list* attrs); ~TableConstructorExpr() { Unref(attrs); } + Attributes* Attrs() { return attrs; } + Val* Eval(Frame* f) const; protected: @@ -767,6 +769,8 @@ public: SetConstructorExpr(ListExpr* constructor_list, attr_list* attrs); ~SetConstructorExpr() { Unref(attrs); } + Attributes* Attrs() { return attrs; } + Val* Eval(Frame* f) const; protected: diff --git a/src/Var.cc b/src/Var.cc index 9c4fb5b978..3526c96550 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -109,6 +109,34 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init, if ( attr ) id->AddAttrs(new Attributes(attr, t, false)); + if ( init ) + { + switch ( init->Tag() ) { + case EXPR_TABLE_CONSTRUCTOR: + { + TableConstructorExpr* ctor = (TableConstructorExpr*) init; + if ( ctor->Attrs() ) + { + ::Ref(ctor->Attrs()); + id->AddAttrs(ctor->Attrs()); + } + } + break; + case EXPR_SET_CONSTRUCTOR: + { + SetConstructorExpr* ctor = (SetConstructorExpr*) init; + if ( ctor->Attrs() ) + { + ::Ref(ctor->Attrs()); + id->AddAttrs(ctor->Attrs()); + } + } + break; + default: + break; + } + } + if ( id->FindAttr(ATTR_PERSISTENT) || id->FindAttr(ATTR_SYNCHRONIZED) ) { if ( dt == VAR_CONST ) diff --git a/testing/btest/Baseline/language.table-init-attrs/output b/testing/btest/Baseline/language.table-init-attrs/output new file mode 100644 index 0000000000..55df002ed0 --- /dev/null +++ b/testing/btest/Baseline/language.table-init-attrs/output @@ -0,0 +1,91 @@ +my_set_ctor_init +{ +test2, +test3, +test4, +test1 +} + +my_table_ctor_init +{ +[2] = test2, +[1] = test1, +[3] = test3 +} +nope + +my_set_init +{ +test2, +test3, +test4, +test1 +} + +my_table_init +{ +[2] = test2, +[4] = test4, +[1] = test1, +[3] = test3 +} +nope + +inception +{ +[0] = { +[13] = bar +} +} +{ +[13] = bar +} +bar +forty-two +{ + +} +we need to go deeper +{ +[0] = { +[13] = bar +} +} +{ +[13] = bar +} +bar +forty-two +{ + +} +we need to go deeper + +local table t1 +{ +[1] = foo +} +foo +nope + +local table t2 +{ +[1] = foo +} +foo +nope + +local table t3 +{ + +} +nope +nope + +local table t4 +{ + +} +nope +nope + diff --git a/testing/btest/language/table-init-attrs.bro b/testing/btest/language/table-init-attrs.bro new file mode 100644 index 0000000000..76d98b9fed --- /dev/null +++ b/testing/btest/language/table-init-attrs.bro @@ -0,0 +1,115 @@ +# @TEST-EXEC: bro -b %INPUT >output +# @TEST-EXEC: btest-diff output + +# set()/table() constructors are allowed to have attributes. When initializing +# an identifier, those attributes should also apply to it. + +const my_set_ctor_init: set[string] = set("test1") &redef; + +redef my_set_ctor_init += { + "test2", + "test3", +}; + +redef my_set_ctor_init += set("test4"); + +const my_table_ctor_init: table[count] of string = table([1] = "test1") &redef &default="nope"; + +redef my_table_ctor_init += { + [2] = "test2", + [3] = "test3", +}; + +# initializer list versions work the same way. + +const my_set_init: set[string] = { "test1" } &redef; + +redef my_set_init += { + "test2", + "test3", +}; + +redef my_set_init += set("test4"); + +const my_table_init: table[count] of string = { [1] = "test1" } &redef &default="nope"; + +redef my_table_init += { + [2] = "test2", + [3] = "test3", +}; + +redef my_table_init += table([4] = "test4"); + +# For tables that yield tables, we can apply attributes to the both other and +# inner tables... + +global inception_table: table[count] of table[count] of string = table( + [0] = table([13] = "bar") &default="forty-two" +) &default=table() &default="we need to go deeper"; + +global inception_table2: table[count] of table[count] of string = { + [0] = table([13] = "bar") &default="forty-two", +} &default=table() &default="we need to go deeper"; + +event bro_init() + { + print "my_set_ctor_init"; + print my_set_ctor_init; + print ""; + print "my_table_ctor_init"; + print my_table_ctor_init; + print my_table_ctor_init[5]; + print ""; + print "my_set_init"; + print my_set_init; + print ""; + print "my_table_init"; + print my_table_init; + print my_table_init[5]; + print ""; + print "inception"; + print inception_table; + print inception_table[0]; + print inception_table[0][13]; + print inception_table[0][42]; + print inception_table[1]; + print inception_table[1][2]; + print inception_table2; + print inception_table2[0]; + print inception_table2[0][13]; + print inception_table2[0][42]; + print inception_table2[1]; + print inception_table2[1][2]; + print ""; + + # just checking attributes on locals works, too + print "local table t1"; + local t1: table[count] of string = table([1] = "foo") &default="nope"; + print t1; + print t1[1]; + print t1[2]; + print ""; + + print "local table t2"; + local t2: table[count] of string = {[1] = "foo"} &default="nope"; + print t2; + print t2[1]; + print t2[2]; + print ""; + + # and for empty initializers... + print "local table t3"; + local t3: table[count] of string = table() &default="nope"; + print t3; + print t3[1]; + print t3[2]; + print ""; + + print "local table t4"; + local t4: table[count] of string = {} &default="nope"; + print t4; + print t4[1]; + print t4[2]; + print ""; + + }