script optimization tracking of functions called by event engine or indirectly

This commit is contained in:
Vern Paxson 2023-12-08 15:09:50 -05:00 committed by Arne Welzel
parent e9b990254a
commit dd91790f1e
6 changed files with 640 additions and 490 deletions

View file

@ -6,461 +6,507 @@
namespace zeek::detail { namespace zeek::detail {
// The following BiFs do not have any script-level side effects. It's // See script_opt/ZAM/maint/README for maintenance of the attributes
// followed by comments listing the BiFs that have been omitted, and why. // in this file.
//
// See script_opt/ZAM/maint/README for maintenance of these lists.
static std::unordered_set<std::string> side_effects_free_BiFs = { // Attributes associated with functions. Currently these are mutually
"Analyzer::__disable_all_analyzers", // exclusive (i.e., no function will have more than one), but for now
"Analyzer::__disable_analyzer", // we use a bitmask-style approach so we can accommodate future attributes
"Analyzer::__enable_analyzer", // that might overlap.
"Analyzer::__has_tag",
"Analyzer::__name", // BiF Functions that are not listed are assumed to have Unknown side effects.
"Analyzer::__register_for_port", // (These are described in comments after the table definition.) Script
"Analyzer::__schedule_analyzer", // functions that are not listed as assumed to not be "special", i.e. known
"Analyzer::__tag", // to the event engine.
"FileExtract::__set_limit",
"Files::__add_analyzer", // Does not change script-level state (though may change internal state).
"Files::__analyzer_enabled", #define ATTR_NO_SCRIPT_SIDE_EFFECTS 0x1
"Files::__analyzer_name",
"Files::__disable_analyzer", // Does not change any Zeek state, internal or external. (May change
"Files::__disable_reassembly", // state outside of Zeek, such as file system elements.) Implies
"Files::__enable_analyzer", // ATTR_NO_SCRIPT_SIDE_EFFECTS.
"Files::__enable_reassembly", #define ATTR_NO_ZEEK_SIDE_EFFECTS 0x2
"Files::__file_exists",
"Files::__lookup_file", // Calls made with the same arguments yield the same results. Implies
"Files::__remove_analyzer", // ATTR_NO_ZEEK_SIDE_EFFECTS.
"Files::__set_reassembly_buffer", #define ATTR_IDEMPOTENT 0x4
"Files::__set_timeout_interval",
"Files::__stop", // The event engine knows about this script function and may call it
"Input::__create_analysis_stream", // during its processing.
"Input::__create_event_stream", #define ATTR_SPECIAL_SCRIPT_FUNC 0x8
"Input::__create_table_stream",
"Input::__force_update", static std::unordered_map<std::string, unsigned int> func_attrs = {
"Input::__remove_stream", // Script functions.
"Log::__add_filter", {"Analyzer::disabling_analyzer", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__create_stream", {"Log::__default_rotation_postprocessor", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__disable_stream", {"Log::empty_post_delay_cb", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__enable_stream", {"Log::log_stream_policy", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__flush", {"Log::rotation_format_func", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__remove_filter", {"Supervisor::stderr_hook", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__remove_stream", {"Supervisor::stdout_hook", ATTR_SPECIAL_SCRIPT_FUNC},
"Log::__set_buf", {"assertion_failure", ATTR_SPECIAL_SCRIPT_FUNC},
"Option::any_set_to_any_vec", {"assertion_result", ATTR_SPECIAL_SCRIPT_FUNC},
"Option::set_change_handler", {"discarder_check_icmp", ATTR_SPECIAL_SCRIPT_FUNC},
"PacketAnalyzer::GTPV1::remove_gtpv1_connection", {"discarder_check_ip", ATTR_SPECIAL_SCRIPT_FUNC},
"PacketAnalyzer::TEREDO::remove_teredo_connection", {"discarder_check_tcp", ATTR_SPECIAL_SCRIPT_FUNC},
"PacketAnalyzer::__disable_analyzer", {"discarder_check_udp", ATTR_SPECIAL_SCRIPT_FUNC},
"PacketAnalyzer::__enable_analyzer", {"from_json_default_key_mapper", ATTR_SPECIAL_SCRIPT_FUNC},
"PacketAnalyzer::__set_ignore_checksums_nets",
"PacketAnalyzer::register_packet_analyzer", // BiFs.
"PacketAnalyzer::register_protocol_detection", {"Analyzer::__disable_all_analyzers", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"PacketAnalyzer::try_register_packet_analyzer_by_name", {"Analyzer::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Pcap::error", {"Analyzer::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Pcap::findalldevs", {"Analyzer::__has_tag", ATTR_IDEMPOTENT},
"Pcap::get_filter_state", {"Analyzer::__name", ATTR_IDEMPOTENT},
"Pcap::get_filter_state_string", {"Analyzer::__register_for_port", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Pcap::install_pcap_filter", {"Analyzer::__schedule_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Pcap::precompile_pcap_filter", {"Analyzer::__tag", ATTR_IDEMPOTENT},
"Reporter::conn_weird", {"FileExtract::__set_limit", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::error", {"Files::__add_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::fatal", {"Files::__analyzer_enabled", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Reporter::fatal_error_with_core", {"Files::__analyzer_name", ATTR_IDEMPOTENT},
"Reporter::file_weird", {"Files::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::flow_weird", {"Files::__disable_reassembly", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::get_weird_sampling_duration", {"Files::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::get_weird_sampling_global_list", {"Files::__enable_reassembly", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::get_weird_sampling_rate", {"Files::__file_exists", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Reporter::get_weird_sampling_threshold", {"Files::__lookup_file", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Reporter::get_weird_sampling_whitelist", {"Files::__remove_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::info", {"Files::__set_reassembly_buffer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::net_weird", {"Files::__set_timeout_interval", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::set_weird_sampling_duration", {"Files::__stop", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::set_weird_sampling_global_list", {"Input::__create_analysis_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::set_weird_sampling_rate", {"Input::__create_event_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::set_weird_sampling_threshold", {"Input::__create_table_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::set_weird_sampling_whitelist", {"Input::__force_update", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Reporter::warning", {"Input::__remove_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Spicy::__resource_usage", {"Log::__add_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Spicy::__toggle_analyzer", {"Log::__create_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__create", {"Log::__delay_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__destroy", {"Log::__disable_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__init_cluster", {"Log::__enable_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__is_supervised", {"Log::__flush", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__is_supervisor", {"Log::__get_delay_queue_size", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Supervisor::__node", {"Log::__remove_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__restart", {"Log::__remove_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__status", {"Log::__set_buf", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Supervisor::__stem_pid", {"Log::__set_max_delay_interval", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__collect_histogram_metrics", {"Log::__set_max_delay_queue_size", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__collect_metrics", {"Option::any_set_to_any_vec", ATTR_IDEMPOTENT},
"Telemetry::__dbl_counter_family", {"Option::set_change_handler", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_counter_inc", {"PacketAnalyzer::GTPV1::remove_gtpv1_connection", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_counter_metric_get_or_add", {"PacketAnalyzer::TEREDO::remove_teredo_connection", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_counter_value", {"PacketAnalyzer::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_gauge_dec", {"PacketAnalyzer::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_gauge_family", {"PacketAnalyzer::__set_ignore_checksums_nets", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_gauge_inc", {"PacketAnalyzer::register_packet_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_gauge_metric_get_or_add", {"PacketAnalyzer::register_protocol_detection", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_gauge_value", {"PacketAnalyzer::try_register_packet_analyzer_by_name", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_histogram_family", {"Pcap::error", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__dbl_histogram_metric_get_or_add", {"Pcap::findalldevs", ATTR_IDEMPOTENT},
"Telemetry::__dbl_histogram_observe", {"Pcap::get_filter_state", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__dbl_histogram_sum", {"Pcap::get_filter_state_string", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__int_counter_family", {"Pcap::install_pcap_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_counter_inc", {"Pcap::precompile_pcap_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_counter_metric_get_or_add", {"Reporter::conn_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_counter_value", {"Reporter::error", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_gauge_dec", {"Reporter::fatal", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_gauge_family", {"Reporter::fatal_error_with_core", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_gauge_inc", {"Reporter::file_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_gauge_metric_get_or_add", {"Reporter::flow_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"Telemetry::__int_gauge_value", {"Reporter::get_weird_sampling_duration", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__int_histogram_family", {"Reporter::get_weird_sampling_global_list", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__int_histogram_metric_get_or_add", {"Reporter::get_weird_sampling_rate", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__int_histogram_observe", {"Reporter::get_weird_sampling_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS},
"Telemetry::__int_histogram_sum", {"Reporter::get_weird_sampling_whitelist", ATTR_NO_ZEEK_SIDE_EFFECTS},
"__init_primary_bifs", {"Reporter::info", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"__init_secondary_bifs", {"Reporter::net_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"active_file", {"Reporter::set_weird_sampling_duration", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"addr_to_counts", {"Reporter::set_weird_sampling_global_list", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"addr_to_ptr_name", {"Reporter::set_weird_sampling_rate", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"addr_to_subnet", {"Reporter::set_weird_sampling_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"all_set", {"Reporter::set_weird_sampling_whitelist", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"anonymize_addr", {"Reporter::warning", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"any_set", {"Spicy::__resource_usage", ATTR_NO_ZEEK_SIDE_EFFECTS},
"backtrace", {"Spicy::__toggle_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bare_mode", {"Supervisor::__create", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_add", {"Supervisor::__destroy", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_basic_init", {"Supervisor::__init_cluster", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_basic_init2", {"Supervisor::__is_supervised", ATTR_IDEMPOTENT},
"bloomfilter_clear", {"Supervisor::__is_supervisor", ATTR_IDEMPOTENT},
"bloomfilter_counting_init", {"Supervisor::__node", ATTR_IDEMPOTENT},
"bloomfilter_decrement", {"Supervisor::__restart", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_internal_state", {"Supervisor::__status", ATTR_NO_ZEEK_SIDE_EFFECTS},
"bloomfilter_intersect", {"Supervisor::__stem_pid", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_lookup", {"Telemetry::__collect_histogram_metrics", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bloomfilter_merge", {"Telemetry::__collect_metrics", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bytestring_to_count", {"Telemetry::__dbl_counter_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bytestring_to_double", {"Telemetry::__dbl_counter_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bytestring_to_float", {"Telemetry::__dbl_counter_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"bytestring_to_hexstr", {"Telemetry::__dbl_counter_value", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"calc_next_rotate", {"Telemetry::__dbl_gauge_dec", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"cat", {"Telemetry::__dbl_gauge_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"cat_sep", {"Telemetry::__dbl_gauge_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"ceil", {"Telemetry::__dbl_gauge_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"check_subnet", {"Telemetry::__dbl_gauge_value", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"clean", {"Telemetry::__dbl_histogram_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"close", {"Telemetry::__dbl_histogram_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"community_id_v1", {"Telemetry::__dbl_histogram_observe", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"compress_path", {"Telemetry::__dbl_histogram_sum", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"connection_exists", {"Telemetry::__int_counter_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"continue_processing", {"Telemetry::__int_counter_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"convert_for_pattern", {"Telemetry::__int_counter_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"count_substr", {"Telemetry::__int_counter_value", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"count_to_double", {"Telemetry::__int_gauge_dec", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"count_to_port", {"Telemetry::__int_gauge_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"count_to_v4_addr", {"Telemetry::__int_gauge_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"counts_to_addr", {"Telemetry::__int_gauge_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"current_analyzer", {"Telemetry::__int_gauge_value", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"current_event_time", {"Telemetry::__int_histogram_family", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"current_time", {"Telemetry::__int_histogram_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"decode_base64", {"Telemetry::__int_histogram_observe", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"decode_base64_conn", {"Telemetry::__int_histogram_sum", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"decode_netbios_name", {"__init_primary_bifs", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"decode_netbios_name_type", {"__init_secondary_bifs", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"disable_event_group", {"active_file", ATTR_NO_ZEEK_SIDE_EFFECTS},
"disable_module_events", {"addr_to_counts", ATTR_IDEMPOTENT},
"do_profiling", {"addr_to_ptr_name", ATTR_IDEMPOTENT},
"double_to_count", {"addr_to_subnet", ATTR_IDEMPOTENT},
"double_to_int", {"all_set", ATTR_IDEMPOTENT},
"double_to_interval", {"anonymize_addr", ATTR_IDEMPOTENT},
"double_to_time", {"any_set", ATTR_IDEMPOTENT},
"dump_current_packet", {"backtrace", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"dump_packet", {"bare_mode", ATTR_IDEMPOTENT},
"dump_rule_stats", {"bloomfilter_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"edit", {"bloomfilter_basic_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"enable_event_group", {"bloomfilter_basic_init2", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"enable_module_events", {"bloomfilter_clear", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"enable_raw_output", {"bloomfilter_counting_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"encode_base64", {"bloomfilter_decrement", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"ends_with", {"bloomfilter_internal_state", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"entropy_test_add", {"bloomfilter_intersect", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"entropy_test_finish", {"bloomfilter_lookup", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"entropy_test_init", {"bloomfilter_merge", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"enum_names", {"bytestring_to_count", ATTR_IDEMPOTENT},
"enum_to_int", {"bytestring_to_double", ATTR_IDEMPOTENT},
"escape_string", {"bytestring_to_float", ATTR_IDEMPOTENT},
"exit", {"bytestring_to_hexstr", ATTR_IDEMPOTENT},
"exp", {"calc_next_rotate", ATTR_NO_ZEEK_SIDE_EFFECTS},
"file_magic", {"cat", ATTR_IDEMPOTENT},
"file_mode", {"cat_sep", ATTR_IDEMPOTENT},
"file_size", {"ceil", ATTR_IDEMPOTENT},
"filter_subnet_table", {"check_subnet", ATTR_IDEMPOTENT},
"find_all", {"clean", ATTR_IDEMPOTENT},
"find_all_ordered", {"close", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"find_entropy", {"community_id_v1", ATTR_IDEMPOTENT},
"find_last", {"compress_path", ATTR_IDEMPOTENT},
"find_str", {"connection_exists", ATTR_NO_ZEEK_SIDE_EFFECTS},
"floor", {"continue_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"flush_all", {"convert_for_pattern", ATTR_IDEMPOTENT},
"fmt", {"count_substr", ATTR_IDEMPOTENT},
"fmt_ftp_port", {"count_to_double", ATTR_IDEMPOTENT},
"fnv1a32", {"count_to_port", ATTR_IDEMPOTENT},
"generate_all_events", {"count_to_v4_addr", ATTR_IDEMPOTENT},
"get_broker_stats", {"counts_to_addr", ATTR_IDEMPOTENT},
"get_conn_stats", {"current_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS},
"get_conn_transport_proto", {"current_event_time", ATTR_NO_ZEEK_SIDE_EFFECTS},
"get_contents_file", {"current_time", ATTR_NO_ZEEK_SIDE_EFFECTS},
"get_current_conn_bytes_threshold", {"decode_base64", ATTR_IDEMPOTENT},
"get_current_conn_duration_threshold", {"decode_base64_conn", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_current_conn_packets_threshold", {"decode_netbios_name", ATTR_IDEMPOTENT},
"get_current_packet", {"decode_netbios_name_type", ATTR_IDEMPOTENT},
"get_current_packet_header", {"disable_event_group", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_dns_stats", {"disable_module_events", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_event_handler_stats", {"do_profiling", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_event_stats", {"double_to_count", ATTR_IDEMPOTENT},
"get_file_analysis_stats", {"double_to_int", ATTR_IDEMPOTENT},
"get_file_name", {"double_to_interval", ATTR_IDEMPOTENT},
"get_gap_stats", {"double_to_time", ATTR_IDEMPOTENT},
"get_identifier_comments", {"dump_current_packet", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_identifier_declaring_script", {"dump_packet", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_login_state", {"dump_rule_stats", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_matcher_stats", {"edit", ATTR_IDEMPOTENT},
"get_net_stats", {"enable_event_group", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_orig_seq", {"enable_module_events", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_package_readme", {"enable_raw_output", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_port_transport_proto", {"encode_base64", ATTR_IDEMPOTENT},
"get_proc_stats", {"ends_with", ATTR_IDEMPOTENT},
"get_reassembler_stats", {"entropy_test_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_record_field_comments", {"entropy_test_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_record_field_declaring_script", {"entropy_test_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_reporter_stats", {"enum_names", ATTR_IDEMPOTENT},
"get_resp_seq", {"enum_to_int", ATTR_IDEMPOTENT},
"get_script_comments", {"escape_string", ATTR_IDEMPOTENT},
"get_thread_stats", {"exit", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"get_timer_stats", {"exp", ATTR_IDEMPOTENT},
"getenv", {"file_magic", ATTR_IDEMPOTENT},
"gethostname", {"file_mode", ATTR_NO_ZEEK_SIDE_EFFECTS},
"getpid", {"file_size", ATTR_NO_ZEEK_SIDE_EFFECTS},
"global_container_footprints", {"filter_subnet_table", ATTR_NO_ZEEK_SIDE_EFFECTS},
"global_ids", {"find_all", ATTR_IDEMPOTENT},
"global_options", {"find_all_ordered", ATTR_IDEMPOTENT},
"gsub", {"find_entropy", ATTR_IDEMPOTENT},
"has_event_group", {"find_last", ATTR_IDEMPOTENT},
"has_module_events", {"find_str", ATTR_IDEMPOTENT},
"have_spicy", {"floor", ATTR_IDEMPOTENT},
"have_spicy_analyzers", {"flush_all", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"haversine_distance", {"fmt", ATTR_IDEMPOTENT},
"hexdump", {"fmt_ftp_port", ATTR_IDEMPOTENT},
"hexstr_to_bytestring", {"fnv1a32", ATTR_IDEMPOTENT},
"hll_cardinality_add", {"generate_all_events", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"hll_cardinality_copy", {"get_broker_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"hll_cardinality_estimate", {"get_conn_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"hll_cardinality_init", {"get_conn_transport_proto", ATTR_IDEMPOTENT},
"hll_cardinality_merge_into", {"get_contents_file", ATTR_NO_ZEEK_SIDE_EFFECTS},
"hrw_weight", {"get_current_conn_bytes_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS},
"identify_data", {"get_current_conn_duration_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS},
"install_dst_addr_filter", {"get_current_conn_packets_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS},
"install_dst_net_filter", {"get_current_packet", ATTR_NO_ZEEK_SIDE_EFFECTS},
"install_src_addr_filter", {"get_current_packet_header", ATTR_NO_ZEEK_SIDE_EFFECTS},
"install_src_net_filter", {"get_dns_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"int_to_count", {"get_event_handler_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"int_to_double", {"get_event_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"interval_to_double", {"get_file_analysis_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_alnum", {"get_file_name", ATTR_IDEMPOTENT},
"is_alpha", {"get_gap_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_ascii", {"get_identifier_comments", ATTR_IDEMPOTENT},
"is_file_analyzer", {"get_identifier_declaring_script", ATTR_IDEMPOTENT},
"is_icmp_port", {"get_login_state", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_local_interface", {"get_matcher_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_num", {"get_net_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_packet_analyzer", {"get_orig_seq", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_processing_suspended", {"get_package_readme", ATTR_IDEMPOTENT},
"is_protocol_analyzer", {"get_port_transport_proto", ATTR_IDEMPOTENT},
"is_remote_event", {"get_proc_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_tcp_port", {"get_reassembler_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_udp_port", {"get_record_field_comments", ATTR_IDEMPOTENT},
"is_v4_addr", {"get_record_field_declaring_script", ATTR_IDEMPOTENT},
"is_v4_subnet", {"get_reporter_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_v6_addr", {"get_resp_seq", ATTR_NO_ZEEK_SIDE_EFFECTS},
"is_v6_subnet", {"get_script_comments", ATTR_IDEMPOTENT},
"is_valid_ip", {"get_thread_stats", ATTR_NO_ZEEK_SIDE_EFFECTS},
"join_string_set", {"get_timer_stats", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"join_string_vec", {"getenv", ATTR_NO_ZEEK_SIDE_EFFECTS},
"levenshtein_distance", {"gethostname", ATTR_IDEMPOTENT},
"ljust", {"getpid", ATTR_IDEMPOTENT},
"ln", {"global_container_footprints", ATTR_NO_ZEEK_SIDE_EFFECTS},
"load_CPP", {"global_ids", ATTR_IDEMPOTENT},
"log10", {"global_options", ATTR_IDEMPOTENT},
"log2", {"gsub", ATTR_IDEMPOTENT},
"lookup_ID", {"has_event_group", ATTR_NO_ZEEK_SIDE_EFFECTS},
"lookup_addr", {"has_module_events", ATTR_NO_ZEEK_SIDE_EFFECTS},
"lookup_autonomous_system", {"have_spicy", ATTR_IDEMPOTENT},
"lookup_connection", {"have_spicy_analyzers", ATTR_IDEMPOTENT},
"lookup_hostname", {"haversine_distance", ATTR_IDEMPOTENT},
"lookup_hostname_txt", {"hexdump", ATTR_IDEMPOTENT},
"lookup_location", {"hexstr_to_bytestring", ATTR_IDEMPOTENT},
"lstrip", {"hll_cardinality_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"mask_addr", {"hll_cardinality_copy", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"match_signatures", {"hll_cardinality_estimate", ATTR_NO_ZEEK_SIDE_EFFECTS},
"matching_subnets", {"hll_cardinality_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"md5_hash", {"hll_cardinality_merge_into", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"md5_hash_finish", {"hrw_weight", ATTR_IDEMPOTENT},
"md5_hash_init", {"identify_data", ATTR_IDEMPOTENT},
"md5_hash_update", {"install_dst_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"md5_hmac", {"install_dst_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"mkdir", {"install_src_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"mmdb_open_asn_db", {"install_src_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"mmdb_open_location_db", {"int_to_count", ATTR_IDEMPOTENT},
"network_time", {"int_to_double", ATTR_IDEMPOTENT},
"open", {"interval_to_double", ATTR_IDEMPOTENT},
"open_for_append", {"is_alnum", ATTR_IDEMPOTENT},
"packet_source", {"is_alpha", ATTR_IDEMPOTENT},
"paraglob_equals", {"is_ascii", ATTR_IDEMPOTENT},
"paraglob_init", {"is_file_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS},
"paraglob_match", {"is_icmp_port", ATTR_IDEMPOTENT},
"parse_distinguished_name", {"is_local_interface", ATTR_IDEMPOTENT},
"parse_eftp_port", {"is_num", ATTR_IDEMPOTENT},
"parse_ftp_epsv", {"is_packet_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS},
"parse_ftp_pasv", {"is_processing_suspended", ATTR_NO_ZEEK_SIDE_EFFECTS},
"parse_ftp_port", {"is_protocol_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS},
"piped_exec", {"is_remote_event", ATTR_IDEMPOTENT},
"port_to_count", {"is_tcp_port", ATTR_IDEMPOTENT},
"pow", {"is_udp_port", ATTR_IDEMPOTENT},
"preserve_prefix", {"is_v4_addr", ATTR_IDEMPOTENT},
"preserve_subnet", {"is_v4_subnet", ATTR_IDEMPOTENT},
"print_raw", {"is_v6_addr", ATTR_IDEMPOTENT},
"ptr_name_to_addr", {"is_v6_subnet", ATTR_IDEMPOTENT},
"rand", {"is_valid_ip", ATTR_IDEMPOTENT},
"raw_bytes_to_v4_addr", {"join_string_set", ATTR_IDEMPOTENT},
"raw_bytes_to_v6_addr", {"join_string_vec", ATTR_IDEMPOTENT},
"reading_live_traffic", {"levenshtein_distance", ATTR_IDEMPOTENT},
"reading_traces", {"ljust", ATTR_IDEMPOTENT},
"record_fields", {"ln", ATTR_IDEMPOTENT},
"record_type_to_vector", {"load_CPP", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"remask_addr", {"log10", ATTR_IDEMPOTENT},
"remove_prefix", {"log2", ATTR_IDEMPOTENT},
"remove_suffix", {"lookup_ID", ATTR_IDEMPOTENT},
"rename", {"lookup_addr", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"reverse", {"lookup_autonomous_system", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"rfind_str", {"lookup_connection", ATTR_NO_ZEEK_SIDE_EFFECTS},
"rjust", {"lookup_hostname", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"rmdir", {"lookup_hostname_txt", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"rotate_file", {"lookup_location", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"rotate_file_by_name", {"lstrip", ATTR_IDEMPOTENT},
"routing0_data_to_addrs", {"mask_addr", ATTR_IDEMPOTENT},
"rstrip", {"match_signatures", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"safe_shell_quote", {"matching_subnets", ATTR_IDEMPOTENT},
"same_object", {"md5_hash", ATTR_IDEMPOTENT},
"sct_verify", {"md5_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_buf", {"md5_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_contents_file", {"md5_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_current_conn_bytes_threshold", {"md5_hmac", ATTR_IDEMPOTENT},
"set_current_conn_duration_threshold", {"mkdir", ATTR_NO_ZEEK_SIDE_EFFECTS},
"set_current_conn_packets_threshold", {"mmdb_open_asn_db", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_file_handle", {"mmdb_open_location_db", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_inactivity_timeout", {"network_time", ATTR_NO_ZEEK_SIDE_EFFECTS},
"set_keys", {"open", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_login_state", {"open_for_append", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_network_time", {"packet_source", ATTR_IDEMPOTENT},
"set_record_packets", {"paraglob_equals", ATTR_IDEMPOTENT},
"set_secret", {"paraglob_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"set_ssl_established", {"paraglob_match", ATTR_IDEMPOTENT},
"setenv", {"parse_distinguished_name", ATTR_IDEMPOTENT},
"sha1_hash", {"parse_eftp_port", ATTR_IDEMPOTENT},
"sha1_hash_finish", {"parse_ftp_epsv", ATTR_IDEMPOTENT},
"sha1_hash_init", {"parse_ftp_pasv", ATTR_IDEMPOTENT},
"sha1_hash_update", {"parse_ftp_port", ATTR_IDEMPOTENT},
"sha256_hash", {"piped_exec", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"sha256_hash_finish", {"port_to_count", ATTR_IDEMPOTENT},
"sha256_hash_init", {"pow", ATTR_IDEMPOTENT},
"sha256_hash_update", {"preserve_prefix", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"skip_further_processing", {"preserve_subnet", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"skip_http_entity_data", {"print_raw", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"skip_smtp_data", {"ptr_name_to_addr", ATTR_IDEMPOTENT},
"split_string", {"rand", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"split_string1", {"raw_bytes_to_v4_addr", ATTR_IDEMPOTENT},
"split_string_all", {"raw_bytes_to_v6_addr", ATTR_IDEMPOTENT},
"split_string_n", {"reading_live_traffic", ATTR_IDEMPOTENT},
"sqrt", {"reading_traces", ATTR_IDEMPOTENT},
"srand", {"record_fields", ATTR_IDEMPOTENT},
"starts_with", {"record_type_to_vector", ATTR_IDEMPOTENT},
"str_smith_waterman", {"remask_addr", ATTR_IDEMPOTENT},
"str_split_indices", {"remove_prefix", ATTR_IDEMPOTENT},
"strcmp", {"remove_suffix", ATTR_IDEMPOTENT},
"strftime", {"rename", ATTR_NO_ZEEK_SIDE_EFFECTS},
"string_cat", {"reverse", ATTR_IDEMPOTENT},
"string_fill", {"rfind_str", ATTR_IDEMPOTENT},
"string_to_ascii_hex", {"rjust", ATTR_IDEMPOTENT},
"string_to_pattern", {"rmdir", ATTR_NO_ZEEK_SIDE_EFFECTS},
"strip", {"rotate_file", ATTR_NO_ZEEK_SIDE_EFFECTS},
"strptime", {"rotate_file_by_name", ATTR_NO_ZEEK_SIDE_EFFECTS},
"strstr", {"routing0_data_to_addrs", ATTR_IDEMPOTENT},
"sub", {"rstrip", ATTR_IDEMPOTENT},
"sub_bytes", {"safe_shell_quote", ATTR_IDEMPOTENT},
"subnet_to_addr", {"same_object", ATTR_IDEMPOTENT},
"subnet_width", {"sct_verify", ATTR_IDEMPOTENT},
"subst_string", {"set_buf", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"suspend_processing", {"set_contents_file", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"swap_case", {"set_current_conn_bytes_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"syslog", {"set_current_conn_duration_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"system", {"set_current_conn_packets_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"system_env", {"set_file_handle", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"table_keys", {"set_inactivity_timeout", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"table_values", {"set_keys", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"terminate", {"set_login_state", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"time_to_double", {"set_network_time", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_addr", {"set_record_packets", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_count", {"set_secret", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_double", {"set_ssl_established", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_int", {"setenv", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_json", {"sha1_hash", ATTR_IDEMPOTENT},
"to_lower", {"sha1_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_port", {"sha1_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_string_literal", {"sha1_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_subnet", {"sha256_hash", ATTR_IDEMPOTENT},
"to_title", {"sha256_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"to_upper", {"sha256_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"topk_add", {"sha256_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"topk_count", {"skip_further_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"topk_epsilon", {"skip_http_entity_data", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"topk_get_top", {"skip_smtp_data", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"topk_init", {"split_string", ATTR_IDEMPOTENT},
"topk_merge", {"split_string1", ATTR_IDEMPOTENT},
"topk_merge_prune", {"split_string_all", ATTR_IDEMPOTENT},
"topk_size", {"split_string_n", ATTR_IDEMPOTENT},
"topk_sum", {"sqrt", ATTR_IDEMPOTENT},
"type_aliases", {"srand", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"type_name", {"starts_with", ATTR_IDEMPOTENT},
"unescape_URI", {"str_smith_waterman", ATTR_IDEMPOTENT},
"uninstall_dst_addr_filter", {"str_split_indices", ATTR_IDEMPOTENT},
"uninstall_dst_net_filter", {"strcmp", ATTR_IDEMPOTENT},
"uninstall_src_addr_filter", {"strftime", ATTR_IDEMPOTENT},
"uninstall_src_net_filter", {"string_cat", ATTR_IDEMPOTENT},
"unique_id", {"string_fill", ATTR_IDEMPOTENT},
"unique_id_from", {"string_to_ascii_hex", ATTR_IDEMPOTENT},
"unlink", {"string_to_pattern", ATTR_IDEMPOTENT},
"uuid_to_string", {"strip", ATTR_IDEMPOTENT},
"val_footprint", {"strptime", ATTR_IDEMPOTENT},
"write_file", {"strstr", ATTR_IDEMPOTENT},
"x509_check_cert_hostname", {"sub", ATTR_IDEMPOTENT},
"x509_check_hostname", {"sub_bytes", ATTR_IDEMPOTENT},
"x509_from_der", {"subnet_to_addr", ATTR_IDEMPOTENT},
"x509_get_certificate_string", {"subnet_width", ATTR_IDEMPOTENT},
"x509_issuer_name_hash", {"subst_string", ATTR_IDEMPOTENT},
"x509_ocsp_verify", {"suspend_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"x509_parse", {"swap_case", ATTR_IDEMPOTENT},
"x509_set_certificate_cache", {"syslog", ATTR_NO_ZEEK_SIDE_EFFECTS},
"x509_set_certificate_cache_hit_callback", {"system", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"x509_spki_hash", {"system_env", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"x509_subject_name_hash", {"table_keys", ATTR_IDEMPOTENT},
"x509_verify", {"table_pattern_matcher_stats", ATTR_IDEMPOTENT},
"zeek_args", {"table_values", ATTR_IDEMPOTENT},
"zeek_is_terminating", {"terminate", ATTR_NO_SCRIPT_SIDE_EFFECTS},
"zeek_version", {"time_to_double", ATTR_IDEMPOTENT},
"zfill", {"to_addr", ATTR_IDEMPOTENT},
{"to_count", ATTR_IDEMPOTENT},
{"to_double", ATTR_IDEMPOTENT},
{"to_int", ATTR_IDEMPOTENT},
{"to_json", ATTR_IDEMPOTENT},
{"to_lower", ATTR_IDEMPOTENT},
{"to_port", ATTR_IDEMPOTENT},
{"to_string_literal", ATTR_IDEMPOTENT},
{"to_subnet", ATTR_IDEMPOTENT},
{"to_title", ATTR_IDEMPOTENT},
{"to_upper", ATTR_IDEMPOTENT},
{"topk_add", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"topk_count", ATTR_IDEMPOTENT},
{"topk_epsilon", ATTR_IDEMPOTENT},
{"topk_get_top", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"topk_init", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"topk_merge", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"topk_merge_prune", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"topk_size", ATTR_IDEMPOTENT},
{"topk_sum", ATTR_IDEMPOTENT},
{"type_aliases", ATTR_IDEMPOTENT},
{"type_name", ATTR_IDEMPOTENT},
{"unescape_URI", ATTR_IDEMPOTENT},
{"uninstall_dst_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"uninstall_dst_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"uninstall_src_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"uninstall_src_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"unique_id", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"unique_id_from", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"unlink", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"uuid_to_string", ATTR_IDEMPOTENT},
{"val_footprint", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"write_file", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"x509_check_cert_hostname", ATTR_IDEMPOTENT},
{"x509_check_hostname", ATTR_IDEMPOTENT},
{"x509_from_der", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"x509_get_certificate_string", ATTR_IDEMPOTENT},
{"x509_issuer_name_hash", ATTR_IDEMPOTENT},
{"x509_ocsp_verify", ATTR_IDEMPOTENT},
{"x509_parse", ATTR_IDEMPOTENT},
{"x509_set_certificate_cache", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"x509_set_certificate_cache_hit_callback", ATTR_NO_SCRIPT_SIDE_EFFECTS},
{"x509_spki_hash", ATTR_IDEMPOTENT},
{"x509_subject_name_hash", ATTR_IDEMPOTENT},
{"x509_verify", ATTR_IDEMPOTENT},
{"zeek_args", ATTR_IDEMPOTENT},
{"zeek_is_terminating", ATTR_NO_ZEEK_SIDE_EFFECTS},
{"zeek_version", ATTR_IDEMPOTENT},
{"zfill", ATTR_IDEMPOTENT},
}; };
// Ones not listed: // Ones not listed:
@ -472,6 +518,9 @@ static std::unordered_set<std::string> side_effects_free_BiFs = {
// Cluster::publish_rr // Cluster::publish_rr
// These call script functions to get topic names. // These call script functions to get topic names.
// //
// Log::__delay
// Can invoke a callback function specified at run-time.
//
// Log::__write // Log::__write
// Calls log policy functions. // Calls log policy functions.
// //
@ -501,6 +550,22 @@ static std::unordered_set<std::string> side_effects_free_BiFs = {
// Some of these have side effects that could be checked for in a specific // Some of these have side effects that could be checked for in a specific
// context, but the gains from doing so likely aren't worth the complexity. // context, but the gains from doing so likely aren't worth the complexity.
bool is_side_effect_free(std::string func_name) { return side_effects_free_BiFs.count(func_name) > 0; } bool is_special_script_func(std::string func_name) {
auto f_attr = func_attrs.find(func_name);
return f_attr != func_attrs.end() && (f_attr->second & ATTR_SPECIAL_SCRIPT_FUNC) != 0;
}
bool is_idempotent(std::string func_name) {
auto f_attr = func_attrs.find(func_name);
return f_attr != func_attrs.end() && (f_attr->second & ATTR_IDEMPOTENT) != 0;
}
bool has_no_script_side_effects(std::string func_name) {
auto f_attr = func_attrs.find(func_name);
if ( f_attr == func_attrs.end() )
return false;
return (f_attr->second & (ATTR_NO_SCRIPT_SIDE_EFFECTS | ATTR_NO_ZEEK_SIDE_EFFECTS | ATTR_IDEMPOTENT)) != 0;
}
} // namespace zeek::detail } // namespace zeek::detail

View file

@ -1,10 +1,6 @@
// See the file "COPYING" in the main distribution directory for copyright. // See the file "COPYING" in the main distribution directory for copyright.
// Utility functions that return information about Zeek functions. Currently // Utility functions that return information about Zeek functions.
// this is limited to information about whether BiFs are side-effect-free
// (from a Zeek scripting perspective), but could be expanded in the future
// to include information about Zeek script functions, idempotency, and the
// like.
#pragma once #pragma once
@ -12,6 +8,17 @@
namespace zeek::detail { namespace zeek::detail {
extern bool is_side_effect_free(std::string func_name); // A "special script function" is one that the event engine explicitly
// knows about.
extern bool is_special_script_func(std::string func_name);
// An idempotent function returns the same value when called with the
// same arguments (and has no meaningful side effects in terms of script-level
// or Zeek-internal state).
extern bool is_idempotent(std::string func_name);
// Whether the given function (currently, just BiFs) has no Zeek-script-level
// side effects.
extern bool has_no_script_side_effects(std::string func_name);
} // namespace zeek::detail } // namespace zeek::detail

View file

@ -5,6 +5,7 @@
#include "zeek/Desc.h" #include "zeek/Desc.h"
#include "zeek/EventRegistry.h" #include "zeek/EventRegistry.h"
#include "zeek/module_util.h" #include "zeek/module_util.h"
#include "zeek/script_opt/FuncInfo.h"
#include "zeek/script_opt/ProfileFunc.h" #include "zeek/script_opt/ProfileFunc.h"
#include "zeek/script_opt/ScriptOpt.h" #include "zeek/script_opt/ScriptOpt.h"
#include "zeek/script_opt/StmtOptInfo.h" #include "zeek/script_opt/StmtOptInfo.h"
@ -23,6 +24,16 @@ void Inliner::Analyze() {
// Prime the call set for each function with the functions it // Prime the call set for each function with the functions it
// directly calls. // directly calls.
for ( auto& f : funcs ) { for ( auto& f : funcs ) {
// For any function explicitly known to the event engine, it can
// be hard to analyze whether there's a possibility that when
// executing the function, doing so will tickle the event engine
// into calling it recursively. So we remove these up front.
//
// We deal with cases where these defaults are overridden to refer
// to some other function below, when we go through indirect functions.
if ( is_special_script_func(f.Func()->Name()) )
continue;
std::unordered_set<const Func*> cs; std::unordered_set<const Func*> cs;
// Aspirational .... // Aspirational ....
@ -40,6 +51,32 @@ void Inliner::Analyze() {
} }
call_set[f.Func()] = cs; call_set[f.Func()] = cs;
for ( auto& ind_func : f.Profile()->IndirectFuncs() ) {
auto& v = ind_func->GetVal();
if ( ! v )
// Global doesn't correspond to an actual function body.
continue;
auto vf = v->AsFunc();
if ( vf->GetKind() != BuiltinFunc::SCRIPT_FUNC )
// Not of analysis interest.
continue;
auto sf = static_cast<const ScriptFunc*>(vf);
// If we knew transitively that the function lead to any
// indirect calls, nor calls to unsafe BiFs that themselves
// might do so, then we could know that this function isn't
// recursive via indirection. It's not clear, however, that
// identifying such cases is worth the trouble, other than
// for cutting down noise from the following recursion report.
if ( report_recursive )
printf("%s is used indirectly, and thus potentially recursively\n", sf->Name());
non_recursive_funcs.erase(sf);
}
} }
// Transitive closure. If we had any self-respect, we'd implement // Transitive closure. If we had any self-respect, we'd implement
@ -332,8 +369,6 @@ ExprPtr Inliner::CheckForInlining(CallExprPtr c) {
auto scope = func_vf->GetScope(); auto scope = func_vf->GetScope();
auto ie = DoInline(func_vf, body, c->ArgsPtr(), scope, ia->second); auto ie = DoInline(func_vf, body, c->ArgsPtr(), scope, ia->second);
printf("inlined %s\n", obj_desc(c.get()).c_str());
if ( ie ) { if ( ie ) {
ie->SetOriginal(c); ie->SetOriginal(c);
did_inline.insert(func_vf.get()); did_inline.insert(func_vf.get());

View file

@ -193,22 +193,21 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
all_globals.insert(id); all_globals.insert(id);
const auto& t = id->GetType(); const auto& t = id->GetType();
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT ) if ( t->Tag() == TYPE_FUNC )
if ( t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT )
events.insert(id->Name()); events.insert(id->Name());
break; break;
} }
// This is a tad ugly. Unfortunately due to the // This is a tad ugly. Unfortunately due to the weird way
// weird way that Zeek function *declarations* work, // that Zeek function *declarations* work, there's no reliable
// there's no reliable way to get the list of // way to get the list of parameters for a function *definition*,
// parameters for a function *definition*, since // since they can have different names than what's present in the
// they can have different names than what's present // declaration. So we identify them directly, by knowing that
// in the declaration. So we identify them directly, // they come at the beginning of the frame ... and being careful
// by knowing that they come at the beginning of the // to avoid misconfusing a lambda capture with a low frame offset
// frame ... and being careful to avoid misconfusing // as a parameter.
// a lambda capture with a low frame offset as a
// parameter.
if ( captures.count(id) == 0 && id->Offset() < num_params ) if ( captures.count(id) == 0 && id->Offset() < num_params )
params.insert(id); params.insert(id);
@ -251,11 +250,25 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
case EXPR_REMOVE_FROM: case EXPR_REMOVE_FROM:
case EXPR_ASSIGN: { case EXPR_ASSIGN: {
auto lhs = e->GetOp1(); auto lhs = e->GetOp1();
bool is_assign = e->Tag() == EXPR_ASSIGN;
if ( is_assign ) {
// Check for this being an assignment to a function (as
// opposed to a call). If so, then the function can be
// used indirectly.
auto rhs = e->GetOp2();
if ( rhs->Tag() == EXPR_NAME ) {
auto& rhs_id = rhs->AsNameExpr()->IdPtr();
const auto& t = rhs_id->GetType();
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_FUNCTION )
indirect_funcs.insert(rhs_id.get());
}
}
if ( lhs->Tag() == EXPR_REF ) if ( lhs->Tag() == EXPR_REF )
lhs = lhs->GetOp1(); lhs = lhs->GetOp1();
else if ( e->Tag() == EXPR_ASSIGN ) else if ( is_assign )
// This isn't a direct assignment, but instead an overloaded // This isn't a direct assignment, but instead an overloaded
// use of "=" such as in a table constructor. // use of "=" such as in a table constructor.
break; break;
@ -267,7 +280,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
auto id = lhs->AsNameExpr()->Id(); auto id = lhs->AsNameExpr()->Id();
TrackAssignment(id); TrackAssignment(id);
if ( e->Tag() == EXPR_ASSIGN ) { if ( is_assign ) {
auto a_e = static_cast<const AssignExpr*>(e); auto a_e = static_cast<const AssignExpr*>(e);
auto& av = a_e->AssignVal(); auto& av = a_e->AssignVal();
if ( av ) if ( av )
@ -287,7 +300,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
// assignment "a[b] = aggr", it's not a[b]'s type but // assignment "a[b] = aggr", it's not a[b]'s type but
// rather a's type. However, for any of the others, // rather a's type. However, for any of the others,
// e.g. "a[b] -= aggr" it is a[b]'s type. // e.g. "a[b] -= aggr" it is a[b]'s type.
if ( e->Tag() == EXPR_ASSIGN ) if ( is_assign )
aggr_mods.insert(lhs_aggr_t.get()); aggr_mods.insert(lhs_aggr_t.get());
else else
aggr_mods.insert(lhs_t.get()); aggr_mods.insert(lhs_t.get());
@ -325,20 +338,39 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
case EXPR_CALL: { case EXPR_CALL: {
auto c = e->AsCallExpr(); auto c = e->AsCallExpr();
auto args = c->Args();
auto f = c->Func(); auto f = c->Func();
if ( f->Tag() != EXPR_NAME ) { const NameExpr* n = nullptr;
const ID* func = nullptr;
if ( f->Tag() == EXPR_NAME ) {
n = f->AsNameExpr();
func = n->Id();
if ( ! func->IsGlobal() )
does_indirect_calls = true; does_indirect_calls = true;
return TC_CONTINUE; }
else
does_indirect_calls = true;
// Check for whether any of the arguments is a bare function.
// If so, then note that that function may be used indirectly,
// unless the function being called is known to be idempotent.
if ( does_indirect_calls || ! is_idempotent(func->Name()) ) {
for ( auto& arg : args->Exprs() )
if ( arg->Tag() == EXPR_NAME ) {
auto& arg_id = arg->AsNameExpr()->IdPtr();
const auto& t = arg_id->GetType();
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_FUNCTION )
indirect_funcs.insert(arg_id.get());
}
} }
auto n = f->AsNameExpr(); if ( does_indirect_calls )
auto func = n->Id(); // We waited on doing this until after checking for
// indirect functions.
if ( ! func->IsGlobal() ) {
does_indirect_calls = true;
return TC_CONTINUE; return TC_CONTINUE;
}
all_globals.insert(func); all_globals.insert(func);
@ -361,7 +393,6 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) {
} }
// Recurse into the arguments. // Recurse into the arguments.
auto args = c->Args();
args->Traverse(this); args->Traverse(this);
// Do the following explicitly, since we won't be recursing // Do the following explicitly, since we won't be recursing
@ -604,7 +635,7 @@ bool ProfileFuncs::GetCallSideEffects(const NameExpr* n, IDSet& non_local_ids, T
auto func = fv->AsFunc(); auto func = fv->AsFunc();
if ( func->GetKind() == Func::BUILTIN_FUNC ) { if ( func->GetKind() == Func::BUILTIN_FUNC ) {
if ( ! is_side_effect_free(func->Name()) ) if ( ! has_no_script_side_effects(func->Name()) )
is_unknown = true; is_unknown = true;
return true; return true;
} }
@ -1137,7 +1168,7 @@ bool ProfileFuncs::DefinitelyHasNoSideEffects(const ExprPtr& e) const {
return false; return false;
for ( auto& b : pf->BiFGlobals() ) for ( auto& b : pf->BiFGlobals() )
if ( ! is_side_effect_free(b->Name()) ) if ( ! has_no_script_side_effects(b->Name()) )
return false; return false;
return true; return true;
@ -1228,7 +1259,7 @@ bool ProfileFuncs::AssessSideEffects(const ProfileFunc* pf, IDSet& non_local_ids
} }
for ( auto& b : pf->BiFGlobals() ) for ( auto& b : pf->BiFGlobals() )
if ( ! is_side_effect_free(b->Name()) ) { if ( ! has_no_script_side_effects(b->Name()) ) {
is_unknown = true; is_unknown = true;
return true; return true;
} }

View file

@ -120,6 +120,7 @@ public:
const std::unordered_set<const SwitchStmt*>& TypeSwitches() const { return type_switches; } const std::unordered_set<const SwitchStmt*>& TypeSwitches() const { return type_switches; }
bool DoesIndirectCalls() const { return does_indirect_calls; } bool DoesIndirectCalls() const { return does_indirect_calls; }
const IDSet& IndirectFuncs() const { return indirect_funcs; }
int NumParams() const { return num_params; } int NumParams() const { return num_params; }
int NumLambdas() const { return lambdas.size(); } int NumLambdas() const { return lambdas.size(); }
@ -271,6 +272,11 @@ protected:
// than simply a function's (global) name. // than simply a function's (global) name.
bool does_indirect_calls = false; bool does_indirect_calls = false;
// Functions (not hooks or event handlers) that are referred to in
// a context other than being called. These might be used elsewhere
// for indirect calls.
IDSet indirect_funcs;
// Additional values present in the body that should be factored // Additional values present in the body that should be factored
// into its hash. // into its hash.
std::vector<p_hash_type> addl_hashes; std::vector<p_hash_type> addl_hashes;

View file

@ -113,12 +113,17 @@ Input::__force_update
Input::__remove_stream Input::__remove_stream
Log::__add_filter Log::__add_filter
Log::__create_stream Log::__create_stream
Log::__delay
Log::__delay_finish
Log::__disable_stream Log::__disable_stream
Log::__enable_stream Log::__enable_stream
Log::__flush Log::__flush
Log::__get_delay_queue_size
Log::__remove_filter Log::__remove_filter
Log::__remove_stream Log::__remove_stream
Log::__set_buf Log::__set_buf
Log::__set_max_delay_interval
Log::__set_max_delay_queue_size
Log::__write Log::__write
Option::any_set_to_any_vec Option::any_set_to_any_vec
Option::set Option::set
@ -489,6 +494,7 @@ syslog
system system
system_env system_env
table_keys table_keys
table_pattern_matcher_stats
table_values table_values
terminate terminate
time_to_double time_to_double