Spicy: Port over to Spicy's new tuple representation.

Includes a fix for supporting CMake 4.0.
This commit is contained in:
Robin Sommer 2025-03-20 11:08:43 +01:00
parent 71305b0009
commit 94ddd7f411
No known key found for this signature in database
GPG key ID: D8187293B3FFE5D0
9 changed files with 111 additions and 141 deletions

View file

@ -18,6 +18,22 @@ if (WIN32)
set(CMAKE_TOOLCHAIN_FILE ${_toolchain} CACHE STRING "Vcpkg toolchain file") set(CMAKE_TOOLCHAIN_FILE ${_toolchain} CACHE STRING "Vcpkg toolchain file")
endif () endif ()
if (APPLE AND CMAKE_VERSION VERSION_GREATER_EQUAL 4.0.0 AND NOT CMAKE_OSX_SYSROOT)
# Spicy needs having CMAKE_OSX_SYSROOT point to the macOS SDK
# path, but starting with CMake 4.0 CMAKE_OSX_SYSROOT is not set
# automatically anymore. So we follow the guidance from the CMake 4.0
# release notes here:
#
# Builds targeting macOS no longer choose any SDK or pass an "-isysroot"
# flag to the compiler by default. [...] users must now specify
# "-DCMAKE_OSX_SYSROOT=macosx" when configuring their build.
#
# Note that this needs to happen before the project() call below, meaning
# we cannot rely on the corresponding code inside the Spicy CMake
# configuration.
set(CMAKE_OSX_SYSROOT "macosx")
endif ()
project(Zeek C CXX) project(Zeek C CXX)
# We want to set ENABLE_DEBUG to ON by default if the build type is Debug. # We want to set ENABLE_DEBUG to ON by default if the build type is Debug.

@ -1 +1 @@
Subproject commit 1650d875a87accce61bb9d8cde7f51f033280acf Subproject commit 26421d12f15d8b16ba6f385bbd47394cc9f9a0df

View file

@ -33,7 +33,7 @@ declare public BroType event_arg_type(EventHandlerPtr handler, uint<64> idx) &cx
declare public Val to_val(any x, BroType target) &cxxname="zeek::spicy::rt::to_val" &have_prototype; declare public Val to_val(any x, BroType target) &cxxname="zeek::spicy::rt::to_val" &have_prototype;
declare public BroType create_base_type(ZeekTypeTag tag) &cxxname="zeek::spicy::rt::create_base_type" &have_prototype; declare public BroType create_base_type(ZeekTypeTag tag) &cxxname="zeek::spicy::rt::create_base_type" &have_prototype;
declare public BroType create_enum_type(string ns, string id, vector<tuple<string, int<64>>> labels) &cxxname="zeek::spicy::rt::create_enum_type" &have_prototype; declare public BroType create_enum_type(string ns, string id, set<tuple<string, int<64>>> labels) &cxxname="zeek::spicy::rt::create_enum_type" &have_prototype;
declare public BroType create_record_type(string ns, string id, vector<RecordField> fields) &cxxname="zeek::spicy::rt::create_record_type" &have_prototype; declare public BroType create_record_type(string ns, string id, vector<RecordField> fields) &cxxname="zeek::spicy::rt::create_record_type" &have_prototype;
declare public RecordField create_record_field(string id, BroType type_, bool is_optional, bool is_log) &cxxname="zeek::spicy::rt::create_record_field" &have_prototype; declare public RecordField create_record_field(string id, BroType type_, bool is_optional, bool is_log) &cxxname="zeek::spicy::rt::create_record_field" &have_prototype;
declare public BroType create_table_type(BroType key, optional<BroType> value = Null) &cxxname="zeek::spicy::rt::create_table_type" &have_prototype; declare public BroType create_table_type(BroType key, optional<BroType> value = Null) &cxxname="zeek::spicy::rt::create_table_type" &have_prototype;

View file

@ -691,7 +691,7 @@ void Manager::InitPostScript() {
// event that will do it for us through a predefined handler. // event that will do it for us through a predefined handler.
zeek::Args vals = Args(); zeek::Args vals = Args();
vals.emplace_back(tag.AsVal()); vals.emplace_back(tag.AsVal());
vals.emplace_back(zeek::spicy::rt::to_val(port_, base_type(TYPE_PORT))); vals.emplace_back(zeek::spicy::rt::to_val(port_, &hilti::rt::type_info::port, base_type(TYPE_PORT)));
EventHandlerPtr handler = event_registry->Register("spicy_analyzer_for_port"); EventHandlerPtr handler = event_registry->Register("spicy_analyzer_for_port");
event_mgr.Enqueue(handler, std::move(vals)); event_mgr.Enqueue(handler, std::move(vals));
}; };

View file

@ -108,7 +108,8 @@ std::string hilti::rt::detail::adl::to_string(const zeek::spicy::rt::ZeekTypeTag
TypePtr rt::create_enum_type( TypePtr rt::create_enum_type(
const std::string& ns, const std::string& id, const std::string& ns, const std::string& id,
const hilti::rt::Vector<std::tuple<std::string, hilti::rt::integer::safe<int64_t>>>& labels) { const hilti::rt::Set<std::tuple<std::optional<std::string>, std::optional<hilti::rt::integer::safe<int64_t>>>>&
labels) {
auto _ = hilti::rt::profiler::start("zeek/rt/create_enum_type"); auto _ = hilti::rt::profiler::start("zeek/rt/create_enum_type");
if ( auto t = findType(TYPE_ENUM, ns, id) ) if ( auto t = findType(TYPE_ENUM, ns, id) )
@ -117,13 +118,14 @@ TypePtr rt::create_enum_type(
auto etype = make_intrusive<EnumType>(ns + "::" + id); auto etype = make_intrusive<EnumType>(ns + "::" + id);
for ( auto [lid, lval] : labels ) { for ( auto [lid, lval] : labels ) {
auto name = ::hilti::rt::fmt("%s_%s", id, lid); assert(lid && lval);
auto name = ::hilti::rt::fmt("%s_%s", id, *lid);
if ( lval == -1 ) if ( *lval == -1 )
// Zeek's enum can't be negative, so swap in max_int for our Undef. // Zeek's enum can't be negative, so swap in max_int for our Undef.
lval = std::numeric_limits<::zeek_int_t>::max(); lval = std::numeric_limits<::zeek_int_t>::max();
etype->AddName(ns, name.c_str(), lval, true); etype->AddName(ns, name.c_str(), *lval, true);
} }
return std::move(etype); return std::move(etype);
@ -393,7 +395,7 @@ std::string rt::uid() {
throw ValueUnavailable("uid() not available in current context"); throw ValueUnavailable("uid() not available in current context");
} }
std::tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> rt::conn_id() { hilti::rt::Tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> rt::conn_id() {
auto _ = hilti::rt::profiler::start("zeek/rt/conn_id"); auto _ = hilti::rt::profiler::start("zeek/rt/conn_id");
static auto convert_address = [](const IPAddr& zaddr) -> hilti::rt::Address { static auto convert_address = [](const IPAddr& zaddr) -> hilti::rt::Address {
@ -424,10 +426,10 @@ std::tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::P
if ( auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie()) ) { if ( auto cookie = static_cast<Cookie*>(hilti::rt::context::cookie()) ) {
if ( auto c = cookie->protocol ) { if ( auto c = cookie->protocol ) {
const auto* conn = c->analyzer->Conn(); const auto* conn = c->analyzer->Conn();
return std::make_tuple(convert_address(conn->OrigAddr()), return hilti::rt::tuple::make(convert_address(conn->OrigAddr()),
convert_port(conn->OrigPort(), conn->ConnTransport()), convert_port(conn->OrigPort(), conn->ConnTransport()),
convert_address(conn->RespAddr()), convert_address(conn->RespAddr()),
convert_port(conn->RespPort(), conn->ConnTransport())); convert_port(conn->RespPort(), conn->ConnTransport()));
} }
} }

View file

@ -14,10 +14,11 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <hilti/rt/deferred-expression.h>
#include <hilti/rt/exception.h> #include <hilti/rt/exception.h>
#include <hilti/rt/extension-points.h> #include <hilti/rt/extension-points.h>
#include <hilti/rt/fmt.h> #include <hilti/rt/fmt.h>
#include <hilti/rt/profiler.h>
#include <hilti/rt/type-info.h>
#include <hilti/rt/types/all.h> #include <hilti/rt/types/all.h>
#include <hilti/rt/util.h> #include <hilti/rt/util.h>
@ -78,6 +79,8 @@ public:
: TypeMismatch(hilti::rt::fmt("Event parameter mismatch, %s", msg)) {} : TypeMismatch(hilti::rt::fmt("Event parameter mismatch, %s", msg)) {}
ParameterMismatch(std::string_view have, const TypePtr& want, std::string_view location = "") ParameterMismatch(std::string_view have, const TypePtr& want, std::string_view location = "")
: ParameterMismatch(_fmt(have, want)) {} : ParameterMismatch(_fmt(have, want)) {}
ParameterMismatch(const hilti::rt::TypeInfo& have, const TypePtr& want, std::string_view location = "")
: ParameterMismatch(_fmt(have.display, want)) {}
private: private:
static std::string _fmt(const std::string_view& have, const TypePtr& want) { static std::string _fmt(const std::string_view& have, const TypePtr& want) {
@ -169,7 +172,8 @@ extern TypePtr create_base_type(ZeekTypeTag tag);
extern TypePtr create_enum_type( extern TypePtr create_enum_type(
const std::string& ns, const std::string& id, const std::string& ns, const std::string& id,
const hilti::rt::Vector<std::tuple<std::string, hilti::rt::integer::safe<int64_t>>>& labels); const hilti::rt::Set<std::tuple<std::optional<std::string>, std::optional<hilti::rt::integer::safe<int64_t>>>>&
labels);
struct RecordField { struct RecordField {
std::string id; /**< name of record field */ std::string id; /**< name of record field */
@ -279,7 +283,7 @@ std::string uid();
/** /**
* Returns the current connection's ID tuple. * Returns the current connection's ID tuple.
*/ */
std::tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> conn_id(); hilti::rt::Tuple<hilti::rt::Address, hilti::rt::Port, hilti::rt::Address, hilti::rt::Port> conn_id();
/** Instructs to Zeek to flip the directionality of the current connecction. */ /** Instructs to Zeek to flip the directionality of the current connecction. */
void flip_roles(); void flip_roles();
@ -488,39 +492,37 @@ void forward_packet(const hilti::rt::integer::safe<uint32_t>& identifier);
hilti::rt::Time network_time(); hilti::rt::Time network_time();
// Forward-declare to_val() functions. // Forward-declare to_val() functions.
template<typename T, typename std::enable_if_t<hilti::rt::is_tuple<T>::value>* = nullptr>
ValPtr to_val(const T& t, const TypePtr& target);
template<typename... Ts> template<typename... Ts>
inline ValPtr to_val(const hilti::rt::Bitfield<Ts...>& v, const TypePtr& target); ValPtr to_val(const hilti::rt::Tuple<Ts...>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename... Ts>
inline ValPtr to_val(const hilti::rt::Bitfield<Ts...>& v, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>* = nullptr> template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>* = nullptr>
ValPtr to_val(const T& t, const TypePtr& target); ValPtr to_val(const T& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>* = nullptr> template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>* = nullptr>
ValPtr to_val(const T& t, const TypePtr& target); ValPtr to_val(const T& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T, typename std::enable_if_t<std::is_enum<T>::value>* = nullptr> template<typename T, typename std::enable_if_t<std::is_enum<T>::value>* = nullptr>
ValPtr to_val(const T& t, const TypePtr& target); ValPtr to_val(const T& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename K, typename V> template<typename K, typename V>
ValPtr to_val(const hilti::rt::Map<K, V>& s, const TypePtr& target); ValPtr to_val(const hilti::rt::Map<K, V>& s, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T> template<typename T>
ValPtr to_val(const hilti::rt::Set<T>& s, const TypePtr& target); ValPtr to_val(const hilti::rt::Set<T>& s, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T, typename Allocator> template<typename T, typename Allocator>
ValPtr to_val(const hilti::rt::Vector<T, Allocator>& v, const TypePtr& target); ValPtr to_val(const hilti::rt::Vector<T, Allocator>& v, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T> template<typename T>
ValPtr to_val(const std::optional<T>& t, const TypePtr& target); ValPtr to_val(const std::optional<T>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T, typename E>
ValPtr to_val(const hilti::rt::DeferredExpression<T, E>& t, const TypePtr& target);
template<typename T> template<typename T>
ValPtr to_val(hilti::rt::integer::safe<T> i, const TypePtr& target); ValPtr to_val(hilti::rt::integer::safe<T> i, const hilti::rt::TypeInfo* ti, const TypePtr& target);
template<typename T> template<typename T>
ValPtr to_val(const hilti::rt::ValueReference<T>& t, const TypePtr& target); ValPtr to_val(const hilti::rt::ValueReference<T>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Bool& b, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Bool& b, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Address& d, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Address& d, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Bytes& b, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Bytes& b, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Interval& t, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Interval& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Port& d, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Port& d, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const hilti::rt::Time& t, const TypePtr& target); inline ValPtr to_val(const hilti::rt::Time& t, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(const std::string& s, const TypePtr& target); inline ValPtr to_val(const std::string& s, const hilti::rt::TypeInfo* ti, const TypePtr& target);
inline ValPtr to_val(double r, const TypePtr& target); inline ValPtr to_val(double r, const hilti::rt::TypeInfo* ti, const TypePtr& target);
/** /**
* Converts a Spicy-side optional value to a Zeek value. This assumes the * Converts a Spicy-side optional value to a Zeek value. This assumes the
@ -528,33 +530,18 @@ inline ValPtr to_val(double r, const TypePtr& target);
* returned with ref count +1. * returned with ref count +1.
*/ */
template<typename T> template<typename T>
inline ValPtr to_val(const std::optional<T>& t, const TypePtr& target) { inline ValPtr to_val(const std::optional<T>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( t.has_value() ) if ( t.has_value() )
return to_val(hilti::rt::optional::value(t), target); return to_val(hilti::rt::optional::value(t), nullptr, target);
return nullptr; return nullptr;
} }
/**
* Converts a Spicy-side DeferredExpression<T,E> value to a Zeek value. Such
* result values are returned by the ``.?`` operator. If the result is not
* set, this will convert into nullptr (which the tuple-to-record to_val()
* picks up on).
*/
template<typename T, typename E>
inline ValPtr to_val(const hilti::rt::DeferredExpression<T, E>& t, const TypePtr& target) {
try {
return to_val(t(), target);
} catch ( const hilti::rt::AttributeNotSet& ) {
return nullptr;
}
}
/** /**
* Converts a Spicy-side string to a Zeek value. The result is returned with * Converts a Spicy-side string to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const std::string& s, const TypePtr& target) { inline ValPtr to_val(const std::string& s, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_STRING ) if ( target->Tag() != TYPE_STRING )
throw ParameterMismatch("string", target); throw ParameterMismatch("string", target);
@ -565,7 +552,7 @@ inline ValPtr to_val(const std::string& s, const TypePtr& target) {
* Converts a Spicy-side bytes instance to a Zeek value. The result is returned with * Converts a Spicy-side bytes instance to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Bytes& b, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Bytes& b, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_STRING ) if ( target->Tag() != TYPE_STRING )
throw ParameterMismatch("string", target); throw ParameterMismatch("string", target);
@ -577,7 +564,7 @@ inline ValPtr to_val(const hilti::rt::Bytes& b, const TypePtr& target) {
* returned with ref count +1. * returned with ref count +1.
*/ */
template<typename T> template<typename T>
inline ValPtr to_val(hilti::rt::integer::safe<T> i, const TypePtr& target) { inline ValPtr to_val(hilti::rt::integer::safe<T> i, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
ValPtr v = nullptr; ValPtr v = nullptr;
if constexpr ( std::is_unsigned<T>::value ) { if constexpr ( std::is_unsigned<T>::value ) {
if ( target->Tag() == TYPE_COUNT ) if ( target->Tag() == TYPE_COUNT )
@ -604,9 +591,9 @@ inline ValPtr to_val(hilti::rt::integer::safe<T> i, const TypePtr& target) {
} }
template<typename T> template<typename T>
ValPtr to_val(const hilti::rt::ValueReference<T>& t, const TypePtr& target) { ValPtr to_val(const hilti::rt::ValueReference<T>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( auto* x = t.get() ) if ( auto* x = t.get() )
return to_val(*x, target); return to_val(*x, nullptr, target);
return nullptr; return nullptr;
} }
@ -615,7 +602,7 @@ ValPtr to_val(const hilti::rt::ValueReference<T>& t, const TypePtr& target) {
* Converts a Spicy-side signed bool to a Zeek value. The result is * Converts a Spicy-side signed bool to a Zeek value. The result is
* returned with ref count +1. * returned with ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Bool& b, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Bool& b, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_BOOL ) if ( target->Tag() != TYPE_BOOL )
throw ParameterMismatch("bool", target); throw ParameterMismatch("bool", target);
@ -626,7 +613,7 @@ inline ValPtr to_val(const hilti::rt::Bool& b, const TypePtr& target) {
* Converts a Spicy-side real to a Zeek value. The result is returned with * Converts a Spicy-side real to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(double r, const TypePtr& target) { inline ValPtr to_val(double r, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_DOUBLE ) if ( target->Tag() != TYPE_DOUBLE )
throw ParameterMismatch("double", target); throw ParameterMismatch("double", target);
@ -637,7 +624,7 @@ inline ValPtr to_val(double r, const TypePtr& target) {
* Converts a Spicy-side address to a Zeek value. The result is returned with * Converts a Spicy-side address to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Address& d, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Address& d, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_ADDR ) if ( target->Tag() != TYPE_ADDR )
throw ParameterMismatch("addr", target); throw ParameterMismatch("addr", target);
@ -654,7 +641,7 @@ inline ValPtr to_val(const hilti::rt::Address& d, const TypePtr& target) {
* Converts a Spicy-side address to a Zeek value. The result is returned with * Converts a Spicy-side address to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Port& p, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Port& p, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_PORT ) if ( target->Tag() != TYPE_PORT )
throw ParameterMismatch("port", target); throw ParameterMismatch("port", target);
@ -673,7 +660,7 @@ inline ValPtr to_val(const hilti::rt::Port& p, const TypePtr& target) {
* Converts a Spicy-side time to a Zeek value. The result is returned with * Converts a Spicy-side time to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Interval& i, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Interval& i, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_INTERVAL ) if ( target->Tag() != TYPE_INTERVAL )
throw ParameterMismatch("interval", target); throw ParameterMismatch("interval", target);
@ -684,7 +671,7 @@ inline ValPtr to_val(const hilti::rt::Interval& i, const TypePtr& target) {
* Converts a Spicy-side time to a Zeek value. The result is returned with * Converts a Spicy-side time to a Zeek value. The result is returned with
* ref count +1. * ref count +1.
*/ */
inline ValPtr to_val(const hilti::rt::Time& t, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Time& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_TIME ) if ( target->Tag() != TYPE_TIME )
throw ParameterMismatch("time", target); throw ParameterMismatch("time", target);
@ -696,14 +683,14 @@ inline ValPtr to_val(const hilti::rt::Time& t, const TypePtr& target) {
* ref count +1. * ref count +1.
*/ */
template<typename T, typename Allocator> template<typename T, typename Allocator>
inline ValPtr to_val(const hilti::rt::Vector<T, Allocator>& v, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Vector<T, Allocator>& v, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_VECTOR && target->Tag() != TYPE_LIST ) if ( target->Tag() != TYPE_VECTOR && target->Tag() != TYPE_LIST )
throw ParameterMismatch("expected vector or list", target); throw ParameterMismatch("expected vector or list", target);
auto vt = cast_intrusive<VectorType>(target); auto vt = cast_intrusive<VectorType>(target);
auto zv = make_intrusive<VectorVal>(vt); auto zv = make_intrusive<VectorVal>(vt);
for ( const auto& i : v ) for ( const auto& i : v )
zv->Assign(zv->Size(), to_val(i, vt->Yield())); zv->Assign(zv->Size(), to_val(i, nullptr, vt->Yield()));
return std::move(zv); return std::move(zv);
} }
@ -713,10 +700,7 @@ inline ValPtr to_val(const hilti::rt::Vector<T, Allocator>& v, const TypePtr& ta
* ref count +1. * ref count +1.
*/ */
template<typename K, typename V> template<typename K, typename V>
inline ValPtr to_val(const hilti::rt::Map<K, V>& m, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Map<K, V>& m, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if constexpr ( hilti::rt::is_tuple<K>::value )
throw ParameterMismatch("internal error: sets with tuples not yet supported in to_val()");
if ( target->Tag() != TYPE_TABLE ) if ( target->Tag() != TYPE_TABLE )
throw ParameterMismatch("map", target); throw ParameterMismatch("map", target);
@ -730,8 +714,8 @@ inline ValPtr to_val(const hilti::rt::Map<K, V>& m, const TypePtr& target) {
auto zv = make_intrusive<TableVal>(tt); auto zv = make_intrusive<TableVal>(tt);
for ( const auto& i : m ) { for ( const auto& i : m ) {
auto k = to_val(i.first, tt->GetIndexTypes()[0]); auto k = to_val(i.first, nullptr, tt->GetIndexTypes()[0]);
auto v = to_val(i.second, tt->Yield()); auto v = to_val(i.second, nullptr, tt->Yield());
zv->Assign(std::move(k), std::move(v)); zv->Assign(std::move(k), std::move(v));
} }
@ -743,7 +727,7 @@ inline ValPtr to_val(const hilti::rt::Map<K, V>& m, const TypePtr& target) {
* ref count +1. * ref count +1.
*/ */
template<typename T> template<typename T>
inline ValPtr to_val(const hilti::rt::Set<T>& s, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Set<T>& s, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_TABLE ) if ( target->Tag() != TYPE_TABLE )
throw ParameterMismatch("set", target); throw ParameterMismatch("set", target);
@ -754,15 +738,11 @@ inline ValPtr to_val(const hilti::rt::Set<T>& s, const TypePtr& target) {
auto zv = make_intrusive<TableVal>(tt); auto zv = make_intrusive<TableVal>(tt);
for ( const auto& i : s ) { for ( const auto& i : s ) {
if constexpr ( hilti::rt::is_tuple<T>::value ) if ( tt->GetIndexTypes().size() != 1 )
throw ParameterMismatch("internal error: sets with tuples not yet supported in to_val()"); throw ParameterMismatch("set with non-tuple elements", target);
else {
if ( tt->GetIndexTypes().size() != 1 )
throw ParameterMismatch("set with non-tuple elements", target);
auto idx = to_val(i, tt->GetIndexTypes()[0]); auto idx = to_val(i, nullptr, tt->GetIndexTypes()[0]);
zv->Assign(std::move(idx), nullptr); zv->Assign(std::move(idx), nullptr);
}
} }
return zv; return zv;
@ -820,18 +800,11 @@ inline void set_record_field(RecordVal* rval, const IntrusivePtr<RecordType>& rt
if ( x.has_value() ) if ( x.has_value() )
set_record_field(rval, rtype, idx, *x); set_record_field(rval, rtype, idx, *x);
} }
else if constexpr ( is_instance<T, hilti::rt::DeferredExpression>::value ) {
try {
set_record_field(rval, rtype, idx, x());
} catch ( const hilti::rt::AttributeNotSet& ) {
// leave unset
}
}
else { else {
ValPtr v = nullptr; ValPtr v = nullptr;
// This may return a nullptr in cases where the field is to be left unset. // This may return a nullptr in cases where the field is to be left unset.
v = to_val(x, rtype->GetFieldType(idx)); v = to_val(x, nullptr, rtype->GetFieldType(idx));
if ( v ) if ( v )
rval->Assign(idx, v); rval->Assign(idx, v);
@ -848,14 +821,14 @@ inline void set_record_field(RecordVal* rval, const IntrusivePtr<RecordType>& rt
* Converts a Spicy-side tuple to a Zeek record value. The result is returned * Converts a Spicy-side tuple to a Zeek record value. The result is returned
* with ref count +1. * with ref count +1.
*/ */
template<typename T, typename std::enable_if_t<hilti::rt::is_tuple<T>::value>*> template<typename... Ts>
inline ValPtr to_val(const T& t, const TypePtr& target) { ValPtr to_val(const hilti::rt::Tuple<Ts...>& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_RECORD ) if ( target->Tag() != TYPE_RECORD )
throw ParameterMismatch("tuple", target); throw ParameterMismatch("tuple", target);
auto rtype = cast_intrusive<RecordType>(target); auto rtype = cast_intrusive<RecordType>(target);
if ( std::tuple_size<T>::value != rtype->NumFields() ) if ( sizeof...(Ts) != rtype->NumFields() )
throw ParameterMismatch("tuple", target); throw ParameterMismatch("tuple", target);
auto rval = make_intrusive<RecordVal>(rtype); auto rval = make_intrusive<RecordVal>(rtype);
@ -870,7 +843,7 @@ inline ValPtr to_val(const T& t, const TypePtr& target) {
* with ref count +1. * with ref count +1.
*/ */
template<typename... Ts> template<typename... Ts>
inline ValPtr to_val(const hilti::rt::Bitfield<Ts...>& v, const TypePtr& target) { inline ValPtr to_val(const hilti::rt::Bitfield<Ts...>& v, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
using Bitfield = hilti::rt::Bitfield<Ts...>; using Bitfield = hilti::rt::Bitfield<Ts...>;
if ( target->Tag() != TYPE_RECORD ) if ( target->Tag() != TYPE_RECORD )
@ -903,7 +876,7 @@ constexpr bool is_optional = is_optional_impl<std::remove_cv_t<std::remove_refer
* with a ref count +1. * with a ref count +1.
*/ */
template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>*> template<typename T, typename std::enable_if_t<std::is_base_of<::hilti::rt::trait::isStruct, T>::value>*>
inline ValPtr to_val(const T& t, const TypePtr& target) { inline ValPtr to_val(const T& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_RECORD ) if ( target->Tag() != TYPE_RECORD )
throw ParameterMismatch("struct", target); throw ParameterMismatch("struct", target);
@ -958,7 +931,7 @@ inline ValPtr to_val(const T& t, const TypePtr& target) {
} }
/** Maps HILTI's `Protocol` enum to Zeek's `transport_proto` enum. */ /** Maps HILTI's `Protocol` enum to Zeek's `transport_proto` enum. */
inline ValPtr to_val_for_transport_proto(int64_t val, const TypePtr& target) { inline ValPtr to_val_for_transport_proto(int64_t val, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
switch ( val ) { switch ( val ) {
case hilti::rt::Protocol::TCP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_TCP); case hilti::rt::Protocol::TCP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_TCP);
case hilti::rt::Protocol::UDP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_UDP); case hilti::rt::Protocol::UDP: return id::transport_proto->GetEnumVal(::TransportProto::TRANSPORT_UDP);
@ -975,7 +948,7 @@ inline ValPtr to_val_for_transport_proto(int64_t val, const TypePtr& target) {
* with ref count +1. * with ref count +1.
*/ */
template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>*> template<typename T, typename std::enable_if_t<std::is_enum<typename T::Value>::value>*>
inline ValPtr to_val(const T& t, const TypePtr& target) { inline ValPtr to_val(const T& t, const hilti::rt::TypeInfo* ti, const TypePtr& target) {
if ( target->Tag() != TYPE_ENUM ) if ( target->Tag() != TYPE_ENUM )
throw ParameterMismatch("enum", target); throw ParameterMismatch("enum", target);
@ -989,7 +962,7 @@ inline ValPtr to_val(const T& t, const TypePtr& target) {
if ( ! std::is_same_v<T, hilti::rt::Protocol> ) if ( ! std::is_same_v<T, hilti::rt::Protocol> )
throw ParameterMismatch(hilti::rt::demangle(typeid(t).name()), target); throw ParameterMismatch(hilti::rt::demangle(typeid(t).name()), target);
return to_val_for_transport_proto(it, target); return to_val_for_transport_proto(it, nullptr, target);
} }
// Zeek's enum can't be negative, so we swap in max_int for our Undef (-1). // Zeek's enum can't be negative, so we swap in max_int for our Undef (-1).
@ -1243,28 +1216,28 @@ inline hilti::rt::Bool record_has_field(const std::string& name, const std::stri
/** Checks if a Zeek set contains a given element. Throws on errors. */ /** Checks if a Zeek set contains a given element. Throws on errors. */
template<typename T> template<typename T>
::hilti::rt::Bool set_contains(const ValSetPtr& v, const T& key) { ::hilti::rt::Bool set_contains(const ValSetPtr& v, const T& key, const hilti::rt::TypeInfo* ktype) {
auto index = v->GetType()->AsTableType()->GetIndexTypes()[0]; auto index = v->GetType()->AsTableType()->GetIndexTypes()[0];
return (v->Find(to_val(key, index)) != nullptr); return (v->Find(to_val(key, ktype, index)) != nullptr);
} }
/** Checks if a Zeek set contains a given element. Throws on errors. */ /** Checks if a Zeek set contains a given element. Throws on errors. */
template<typename T> template<typename T>
::hilti::rt::Bool set_contains(const std::string& name, const T& key) { ::hilti::rt::Bool set_contains(const std::string& name, const T& key, const hilti::rt::TypeInfo* ktype) {
return set_contains(get_set(name), key); return set_contains(get_set(name), key, ktype);
} }
/** Checks if a Zeek table contains a given element. Throws on errors. */ /** Checks if a Zeek table contains a given element. Throws on errors. */
template<typename T> template<typename T>
::hilti::rt::Bool table_contains(const ValTablePtr& v, const T& key) { ::hilti::rt::Bool table_contains(const ValTablePtr& v, const T& key, const hilti::rt::TypeInfo* ktype) {
auto index = v->GetType()->AsTableType()->GetIndexTypes()[0]; auto index = v->GetType()->AsTableType()->GetIndexTypes()[0];
return (v->Find(to_val(key, index)) != nullptr); return (v->Find(to_val(key, ktype, index)) != nullptr);
} }
/** Check if a Zeek table contains a given element. Throws on errors. */ /** Check if a Zeek table contains a given element. Throws on errors. */
template<typename T> template<typename T>
::hilti::rt::Bool table_contains(const std::string& name, const T& key) { ::hilti::rt::Bool table_contains(const std::string& name, const T& key, const hilti::rt::TypeInfo* ktype) {
return table_contains(get_table(name), key); return table_contains(get_table(name), key, ktype);
} }
/** /**
@ -1272,9 +1245,10 @@ template<typename T>
* not exist. Throws on other errors. * not exist. Throws on other errors.
*/ */
template<typename T> template<typename T>
std::optional<::zeek::ValPtr> table_lookup(const zeek::spicy::rt::ValTablePtr& v, const T& key) { std::optional<::zeek::ValPtr> table_lookup(const zeek::spicy::rt::ValTablePtr& v, const T& key,
const hilti::rt::TypeInfo* ktype) {
auto index = v->GetType()->AsTableType()->GetIndexTypes()[0]; auto index = v->GetType()->AsTableType()->GetIndexTypes()[0];
if ( auto x = v->FindOrDefault(to_val(key, index)) ) if ( auto x = v->FindOrDefault(to_val(key, ktype, index)) )
return x; return x;
else else
return {}; return {};
@ -1285,8 +1259,8 @@ std::optional<::zeek::ValPtr> table_lookup(const zeek::spicy::rt::ValTablePtr& v
* not exist. Throws on other errors. * not exist. Throws on other errors.
*/ */
template<typename T> template<typename T>
std::optional<::zeek::ValPtr> table_lookup(const std::string& name, const T& key) { std::optional<::zeek::ValPtr> table_lookup(const std::string& name, const T& key, const hilti::rt::TypeInfo* ktype) {
return table_lookup(get_table(name), key); return table_lookup(get_table(name), key, ktype);
} }
/** Returns a Zeek vector element. Throws on errors. */ /** Returns a Zeek vector element. Throws on errors. */

View file

@ -1204,33 +1204,12 @@ bool GlueCompiler::PopulateEvents() {
#include <spicy/ast/visitor.h> #include <spicy/ast/visitor.h>
// Helper visitor to wrap expressions using the TryMember operator into a
// "deferred" expression.
class WrapTryMemberVisitor : public spicy::visitor::MutatingPostOrder {
public:
WrapTryMemberVisitor(Builder* builder, bool catch_exception)
: spicy::visitor::MutatingPostOrder(builder, logging::debug::GlueCompiler), _catch_exception(catch_exception) {}
void operator()(hilti::expression::UnresolvedOperator* n) final {
if ( n->kind() == hilti::operator_::Kind::TryMember )
replaceNode(n, builder()->expressionDeferred(n->as<hilti::Expression>(), _catch_exception), "wrap .?");
}
private:
bool _catch_exception;
};
static hilti::Result<hilti::Expression*> parseArgument(Builder* builder, const std::string& expression, static hilti::Result<hilti::Expression*> parseArgument(Builder* builder, const std::string& expression,
bool catch_exception, const hilti::Meta& meta) { bool catch_exception, const hilti::Meta& meta) {
auto expr = ::spicy::builder::parseExpression(builder, expression, meta); auto expr = ::spicy::builder::parseExpression(builder, expression, meta);
if ( ! expr ) if ( ! expr )
return hilti::result::Error(hilti::util::fmt("error parsing event argument expression '%s'", expression)); return hilti::result::Error(hilti::util::fmt("error parsing event argument expression '%s'", expression));
// If the expression uses the ".?" operator, we need to defer evaluation
// so that we can handle potential exceptions at runtime.
auto v = WrapTryMemberVisitor(builder, catch_exception);
spicy::visitor::visit(v, *expr);
return expr; return expr;
} }
@ -1538,7 +1517,7 @@ struct VisitorZeekType : spicy::visitor::PreOrder {
}); });
auto tmp = builder->addTmp(tmpName("labels", id()), auto tmp = builder->addTmp(tmpName("labels", id()),
builder->typeVector( builder->typeSet(
builder->qualifiedType(builder->typeTuple(hilti::QualifiedTypes{ builder->qualifiedType(builder->typeTuple(hilti::QualifiedTypes{
builder->qualifiedType(builder->typeString(), builder->qualifiedType(builder->typeString(),
hilti::Constness::Const), hilti::Constness::Const),
@ -1547,9 +1526,8 @@ struct VisitorZeekType : spicy::visitor::PreOrder {
hilti::Constness::Const))); hilti::Constness::Const)));
for ( const auto& l : t->labels() ) for ( const auto& l : t->labels() )
builder->addMemberCall(tmp, "push_back", builder->addExpression(builder->add(tmp, builder->tuple({builder->stringMutable(l->id().str()),
{builder->tuple( builder->integer(l->value())})));
{builder->stringLiteral(l->id().str()), builder->integer(l->value())})});
result(builder->call("zeek_rt::create_enum_type", {builder->stringMutable(id().namespace_().str()), result(builder->call("zeek_rt::create_enum_type", {builder->stringMutable(id().namespace_().str()),
builder->stringMutable(id().local().str()), tmp})); builder->stringMutable(id().local().str()), tmp}));

View file

@ -1,7 +1,7 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
== spicyz == spicyz
::hilti::rt::print("have zeek"s, ::hilti::rt::Bool(true)); ::hilti::rt::print("have zeek"s, &::hilti::rt::type_info::string, ::hilti::rt::Bool(true));
::hilti::rt::print("have spicy version"s, ::hilti::rt::Bool(true)); ::hilti::rt::print("have spicy version"s, &::hilti::rt::type_info::string, ::hilti::rt::Bool(true));
::hilti::rt::print("have spicy version >= 0.4"s, ::hilti::rt::Bool(true)); ::hilti::rt::print("have spicy version >= 0.4"s, &::hilti::rt::type_info::string, ::hilti::rt::Bool(true));
::hilti::rt::print("not have spicy version >= 4"s, ::hilti::rt::Bool(true)); ::hilti::rt::print("not have spicy version >= 4"s, &::hilti::rt::type_info::string, ::hilti::rt::Bool(true));
::hilti::rt::print("have zeek and zeek version > 1.0"s, ::hilti::rt::Bool(true)); ::hilti::rt::print("have zeek and zeek version > 1.0"s, &::hilti::rt::type_info::string, ::hilti::rt::Bool(true));

View file

@ -5,5 +5,5 @@
[i=4, s=<uninitialized>] [i=4, s=<uninitialized>]
[zeek] [SPICY_SSH/3/orig] -> event ssh::banner((1, b"OpenSSH_3.8.1p1")) [zeek] [SPICY_SSH/3/orig] -> event ssh::banner((1, b"OpenSSH_3.8.1p1"))
[zeek] [SPICY_SSH/3/orig] -> event ssh::banner((2, b"OpenSSH_3.8.1p1")) [zeek] [SPICY_SSH/3/orig] -> event ssh::banner((2, b"OpenSSH_3.8.1p1"))
[zeek] [SPICY_SSH/3/orig] -> event ssh::banner((3, b"")) [zeek] [SPICY_SSH/3/orig] -> event ssh::banner((3, (not set)))
[zeek] [SPICY_SSH/3/orig] -> event ssh::banner((4, Null)) [zeek] [SPICY_SSH/3/orig] -> event ssh::banner((4, Null))