diff --git a/CHANGES b/CHANGES index 9e455af752..8d89240b01 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +6.1.0-dev.293 | 2023-08-11 10:34:52 -0700 + + * Fix conversion with record types (Tim Wojtulewicz, Corelight) + + * Add conversion between set and vector using 'as' keyword (Tim Wojtulewicz, Corelight) + + * Add std::move for a couple of variables passed by value (Tim Wojtulewicz, Corelight) + 6.1.0-dev.289 | 2023-08-11 09:52:24 -0700 * Modbus: Add early return in case of data being too short to parse (Tim Wojtulewicz, Corelight) diff --git a/NEWS b/NEWS index 3b161840f2..52245b7dc9 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,11 @@ New Functionality modules by prefixing their names with ``::``. Previously, these required an explicit ``GLOBAL::`` prefix to be used. Using ``GLOBAL::`` has been deprecated. +- The ``as`` keyword now supports casting between ``set`` and ``vector`` values + with the same element type. Converting ``set`` values with multiple index + values is not supported. We plan to extend the use of the ``as`` keyword to + support more type conversions in the future. + Changed Functionality --------------------- diff --git a/VERSION b/VERSION index a353ada4ed..12b031616e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.1.0-dev.289 +6.1.0-dev.293 diff --git a/src/Expr.cc b/src/Expr.cc index 6d16c114ce..d001706196 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -3703,7 +3703,7 @@ void TableConstructorExpr::ExprDescribe(ODesc* d) const SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, std::unique_ptr> arg_attrs, TypePtr arg_type, AttributesPtr arg_attrs2) - : UnaryExpr(EXPR_SET_CONSTRUCTOR, expand_op(constructor_list, arg_type)) + : UnaryExpr(EXPR_SET_CONSTRUCTOR, expand_op(std::move(constructor_list), arg_type)) { if ( IsError() ) return; @@ -3737,7 +3737,7 @@ SetConstructorExpr::SetConstructorExpr(ListExprPtr constructor_list, if ( arg_attrs ) SetAttrs(make_intrusive(std::move(*arg_attrs), type, false, false)); else - SetAttrs(arg_attrs2); + SetAttrs(std::move(arg_attrs2)); const auto& indices = type->AsTableType()->GetIndices()->GetTypes(); ExprPList& cle = op->AsListExpr()->Exprs(); diff --git a/src/Val.cc b/src/Val.cc index 789e361cdd..f8aa0c6309 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -4282,9 +4282,80 @@ ValPtr cast_value_to_type(Val* v, Type* t) return static_cast(dv.get())->castTo(t); } + // Allow casting between sets and vectors if the yield types are the same. + if ( v->GetType()->IsSet() && IsVector(t->Tag()) ) + { + auto set_type = v->GetType(); + auto indices = set_type->GetIndices(); + + if ( indices->GetTypes().size() > 1 ) + return nullptr; + + auto ret_type = IntrusivePtr{NewRef{}, t->AsVectorType()}; + auto ret = make_intrusive(ret_type); + + auto* table = v->AsTable(); + auto* tval = v->AsTableVal(); + int index = 0; + for ( const auto& te : *table ) + { + auto k = te.GetHashKey(); + auto lv = tval->RecreateIndex(*k); + ValPtr entry_key = lv->Length() == 1 ? lv->Idx(0) : lv; + ret->Assign(index, entry_key); + index++; + } + + return ret; + } + else if ( IsVector(v->GetType()->Tag()) && t->IsSet() ) + { + auto ret_type = IntrusivePtr{NewRef{}, t->AsSetType()}; + auto ret = make_intrusive(ret_type); + + auto vv = v->AsVectorVal(); + size_t size = vv->Size(); + + for ( size_t i = 0; i < size; i++ ) + { + auto ve = vv->ValAt(i); + ret->Assign(std::move(ve), nullptr); + } + + return ret; + } + return nullptr; } +static bool can_cast_set_and_vector(const Type* t1, const Type* t2) + { + const TableType* st = nullptr; + const VectorType* vt = nullptr; + + if ( t1->IsSet() && IsVector(t2->Tag()) ) + { + st = t1->AsSetType(); + vt = t2->AsVectorType(); + } + else if ( IsVector(t1->Tag()) && t2->IsSet() ) + { + st = t2->AsSetType(); + vt = t1->AsVectorType(); + } + + if ( st && vt ) + { + auto set_indices = st->GetIndices()->GetTypes(); + if ( set_indices.size() > 1 ) + return false; + + return same_type(set_indices[0], vt->Yield()); + } + + return false; + } + bool can_cast_value_to_type(const Val* v, Type* t) { // Note: when changing this function, adapt all three of @@ -4308,6 +4379,10 @@ bool can_cast_value_to_type(const Val* v, Type* t) return static_cast(dv.get())->canCastTo(t); } + // Allow casting between sets and vectors if the yield types are the same. + if ( can_cast_set_and_vector(v->GetType().get(), t) ) + return true; + return false; } @@ -4327,6 +4402,10 @@ bool can_cast_value_to_type(const Type* s, Type* t) // will. return true; + // Allow casting between sets and vectors if the yield types are the same. + if ( can_cast_set_and_vector(s, t) ) + return true; + return false; } diff --git a/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr b/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr new file mode 100644 index 0000000000..42446a02a8 --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions-errors/.stderr @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +error in <...>/vector-set-conversions-errors.zeek, line 8: cast not supported (v1 as set[addr]) +error in <...>/vector-set-conversions-errors.zeek, line 15: cast not supported (s2 as vector of addr) +error in <...>/vector-set-conversions-errors.zeek, line 22: cast not supported (s3 as vector of port) diff --git a/testing/btest/Baseline/language.vector-set-conversions-errors/out b/testing/btest/Baseline/language.vector-set-conversions-errors/out new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions-errors/out @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/language.vector-set-conversions/.stderr b/testing/btest/Baseline/language.vector-set-conversions/.stderr new file mode 100644 index 0000000000..49d861c74c --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions/.stderr @@ -0,0 +1 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. diff --git a/testing/btest/Baseline/language.vector-set-conversions/out b/testing/btest/Baseline/language.vector-set-conversions/out new file mode 100644 index 0000000000..85e5403a77 --- /dev/null +++ b/testing/btest/Baseline/language.vector-set-conversions/out @@ -0,0 +1,39 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +vector to set +[1, 1, 1, 2, 2, 3, 3, 4] +{ +4, +2, +3, +1 +} + +set to vector (count) +{ +4, +2, +3, +1 +} +[4, 2, 3, 1] + +set to vector (port) +{ +23/tcp, +21/tcp +} +[23/tcp, 21/tcp] + +set to vector (record) +{ +[a=a, b=b], +[a=a1, b=b1] +} +{ +[a=a, b=b], +[a=a1, b=b1] +} + +vector to set (record) +[[a=a, b=b], [a=a1, b=b1]] +[[a=a, b=b], [a=a1, b=b1]] diff --git a/testing/btest/language/vector-set-conversions-errors.zeek b/testing/btest/language/vector-set-conversions-errors.zeek new file mode 100644 index 0000000000..20d199269a --- /dev/null +++ b/testing/btest/language/vector-set-conversions-errors.zeek @@ -0,0 +1,24 @@ +# @TEST-DOC: Test error cases while converting between sets and vectorswith the 'as' keyword +# @TEST-EXEC-FAIL: zeek -b %INPUT > out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: TEST_DIFF_CANONIFIER="$SCRIPTS/diff-remove-abspath" btest-diff .stderr + +print("vector to set: type mismatch"); +local v1 = vector(1, 1, 1, 2, 2, 3, 3, 4); +local s1 = v1 as set[addr]; +print(v1); +print(s1); + +print(""); +print("set to vector: type mismatch"); +local s2 = set(1, 2, 3, 4); +local v2 = s2 as vector of addr; +print(s2); +print(v2); + +print(""); +print("set to vector: multiple indices"); +local s3: set[port,string] = { [21/tcp, "ftp"], [23/tcp, "telnet"] }; +local v3 = s3 as vector of port; +print(s3); +print(v3); diff --git a/testing/btest/language/vector-set-conversions.zeek b/testing/btest/language/vector-set-conversions.zeek new file mode 100644 index 0000000000..5efa2e4c6d --- /dev/null +++ b/testing/btest/language/vector-set-conversions.zeek @@ -0,0 +1,42 @@ +# @TEST-DOC: Tests converting between sets and vectors with the 'as' keyword +# @TEST-EXEC: zeek -b %INPUT > out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff .stderr + +type r: record { + a: string; + b: string; +}; + +print("vector to set"); +local v1 = vector(1, 1, 1, 2, 2, 3, 3, 4); +local s1 = v1 as set[count]; +print(v1); +print(s1); + +print(""); +print("set to vector (count)"); +local s2 = set(1, 2, 3, 4); +local v2 = s2 as vector of count; +print(s2); +print(v2); + +print(""); +print("set to vector (port)"); +local s3 = set(21/tcp, 23/tcp); +local v3 = s3 as vector of port; +print(s3); +print(v3); + +local s: set[r] = set([$a="a", $b="b"], [$a="a1", $b="b1"]); +local v: vector of r = vector([$a="a", $b="b"], [$a="a1", $b="b1"]); + +print(""); +print("set to vector (record)"); +print s; +print v as set[r]; + +print(""); +print("vector to set (record)"); +print v; +print s as vector of r;