diff --git a/src/script_opt/FuncInfo.cc b/src/script_opt/FuncInfo.cc index 57730670e0..e27dc8282c 100644 --- a/src/script_opt/FuncInfo.cc +++ b/src/script_opt/FuncInfo.cc @@ -6,461 +6,507 @@ namespace zeek::detail { -// The following BiFs do not have any script-level side effects. It's -// followed by comments listing the BiFs that have been omitted, and why. -// -// See script_opt/ZAM/maint/README for maintenance of these lists. +// See script_opt/ZAM/maint/README for maintenance of the attributes +// in this file. -static std::unordered_set side_effects_free_BiFs = { - "Analyzer::__disable_all_analyzers", - "Analyzer::__disable_analyzer", - "Analyzer::__enable_analyzer", - "Analyzer::__has_tag", - "Analyzer::__name", - "Analyzer::__register_for_port", - "Analyzer::__schedule_analyzer", - "Analyzer::__tag", - "FileExtract::__set_limit", - "Files::__add_analyzer", - "Files::__analyzer_enabled", - "Files::__analyzer_name", - "Files::__disable_analyzer", - "Files::__disable_reassembly", - "Files::__enable_analyzer", - "Files::__enable_reassembly", - "Files::__file_exists", - "Files::__lookup_file", - "Files::__remove_analyzer", - "Files::__set_reassembly_buffer", - "Files::__set_timeout_interval", - "Files::__stop", - "Input::__create_analysis_stream", - "Input::__create_event_stream", - "Input::__create_table_stream", - "Input::__force_update", - "Input::__remove_stream", - "Log::__add_filter", - "Log::__create_stream", - "Log::__disable_stream", - "Log::__enable_stream", - "Log::__flush", - "Log::__remove_filter", - "Log::__remove_stream", - "Log::__set_buf", - "Option::any_set_to_any_vec", - "Option::set_change_handler", - "PacketAnalyzer::GTPV1::remove_gtpv1_connection", - "PacketAnalyzer::TEREDO::remove_teredo_connection", - "PacketAnalyzer::__disable_analyzer", - "PacketAnalyzer::__enable_analyzer", - "PacketAnalyzer::__set_ignore_checksums_nets", - "PacketAnalyzer::register_packet_analyzer", - "PacketAnalyzer::register_protocol_detection", - "PacketAnalyzer::try_register_packet_analyzer_by_name", - "Pcap::error", - "Pcap::findalldevs", - "Pcap::get_filter_state", - "Pcap::get_filter_state_string", - "Pcap::install_pcap_filter", - "Pcap::precompile_pcap_filter", - "Reporter::conn_weird", - "Reporter::error", - "Reporter::fatal", - "Reporter::fatal_error_with_core", - "Reporter::file_weird", - "Reporter::flow_weird", - "Reporter::get_weird_sampling_duration", - "Reporter::get_weird_sampling_global_list", - "Reporter::get_weird_sampling_rate", - "Reporter::get_weird_sampling_threshold", - "Reporter::get_weird_sampling_whitelist", - "Reporter::info", - "Reporter::net_weird", - "Reporter::set_weird_sampling_duration", - "Reporter::set_weird_sampling_global_list", - "Reporter::set_weird_sampling_rate", - "Reporter::set_weird_sampling_threshold", - "Reporter::set_weird_sampling_whitelist", - "Reporter::warning", - "Spicy::__resource_usage", - "Spicy::__toggle_analyzer", - "Supervisor::__create", - "Supervisor::__destroy", - "Supervisor::__init_cluster", - "Supervisor::__is_supervised", - "Supervisor::__is_supervisor", - "Supervisor::__node", - "Supervisor::__restart", - "Supervisor::__status", - "Supervisor::__stem_pid", - "Telemetry::__collect_histogram_metrics", - "Telemetry::__collect_metrics", - "Telemetry::__dbl_counter_family", - "Telemetry::__dbl_counter_inc", - "Telemetry::__dbl_counter_metric_get_or_add", - "Telemetry::__dbl_counter_value", - "Telemetry::__dbl_gauge_dec", - "Telemetry::__dbl_gauge_family", - "Telemetry::__dbl_gauge_inc", - "Telemetry::__dbl_gauge_metric_get_or_add", - "Telemetry::__dbl_gauge_value", - "Telemetry::__dbl_histogram_family", - "Telemetry::__dbl_histogram_metric_get_or_add", - "Telemetry::__dbl_histogram_observe", - "Telemetry::__dbl_histogram_sum", - "Telemetry::__int_counter_family", - "Telemetry::__int_counter_inc", - "Telemetry::__int_counter_metric_get_or_add", - "Telemetry::__int_counter_value", - "Telemetry::__int_gauge_dec", - "Telemetry::__int_gauge_family", - "Telemetry::__int_gauge_inc", - "Telemetry::__int_gauge_metric_get_or_add", - "Telemetry::__int_gauge_value", - "Telemetry::__int_histogram_family", - "Telemetry::__int_histogram_metric_get_or_add", - "Telemetry::__int_histogram_observe", - "Telemetry::__int_histogram_sum", - "__init_primary_bifs", - "__init_secondary_bifs", - "active_file", - "addr_to_counts", - "addr_to_ptr_name", - "addr_to_subnet", - "all_set", - "anonymize_addr", - "any_set", - "backtrace", - "bare_mode", - "bloomfilter_add", - "bloomfilter_basic_init", - "bloomfilter_basic_init2", - "bloomfilter_clear", - "bloomfilter_counting_init", - "bloomfilter_decrement", - "bloomfilter_internal_state", - "bloomfilter_intersect", - "bloomfilter_lookup", - "bloomfilter_merge", - "bytestring_to_count", - "bytestring_to_double", - "bytestring_to_float", - "bytestring_to_hexstr", - "calc_next_rotate", - "cat", - "cat_sep", - "ceil", - "check_subnet", - "clean", - "close", - "community_id_v1", - "compress_path", - "connection_exists", - "continue_processing", - "convert_for_pattern", - "count_substr", - "count_to_double", - "count_to_port", - "count_to_v4_addr", - "counts_to_addr", - "current_analyzer", - "current_event_time", - "current_time", - "decode_base64", - "decode_base64_conn", - "decode_netbios_name", - "decode_netbios_name_type", - "disable_event_group", - "disable_module_events", - "do_profiling", - "double_to_count", - "double_to_int", - "double_to_interval", - "double_to_time", - "dump_current_packet", - "dump_packet", - "dump_rule_stats", - "edit", - "enable_event_group", - "enable_module_events", - "enable_raw_output", - "encode_base64", - "ends_with", - "entropy_test_add", - "entropy_test_finish", - "entropy_test_init", - "enum_names", - "enum_to_int", - "escape_string", - "exit", - "exp", - "file_magic", - "file_mode", - "file_size", - "filter_subnet_table", - "find_all", - "find_all_ordered", - "find_entropy", - "find_last", - "find_str", - "floor", - "flush_all", - "fmt", - "fmt_ftp_port", - "fnv1a32", - "generate_all_events", - "get_broker_stats", - "get_conn_stats", - "get_conn_transport_proto", - "get_contents_file", - "get_current_conn_bytes_threshold", - "get_current_conn_duration_threshold", - "get_current_conn_packets_threshold", - "get_current_packet", - "get_current_packet_header", - "get_dns_stats", - "get_event_handler_stats", - "get_event_stats", - "get_file_analysis_stats", - "get_file_name", - "get_gap_stats", - "get_identifier_comments", - "get_identifier_declaring_script", - "get_login_state", - "get_matcher_stats", - "get_net_stats", - "get_orig_seq", - "get_package_readme", - "get_port_transport_proto", - "get_proc_stats", - "get_reassembler_stats", - "get_record_field_comments", - "get_record_field_declaring_script", - "get_reporter_stats", - "get_resp_seq", - "get_script_comments", - "get_thread_stats", - "get_timer_stats", - "getenv", - "gethostname", - "getpid", - "global_container_footprints", - "global_ids", - "global_options", - "gsub", - "has_event_group", - "has_module_events", - "have_spicy", - "have_spicy_analyzers", - "haversine_distance", - "hexdump", - "hexstr_to_bytestring", - "hll_cardinality_add", - "hll_cardinality_copy", - "hll_cardinality_estimate", - "hll_cardinality_init", - "hll_cardinality_merge_into", - "hrw_weight", - "identify_data", - "install_dst_addr_filter", - "install_dst_net_filter", - "install_src_addr_filter", - "install_src_net_filter", - "int_to_count", - "int_to_double", - "interval_to_double", - "is_alnum", - "is_alpha", - "is_ascii", - "is_file_analyzer", - "is_icmp_port", - "is_local_interface", - "is_num", - "is_packet_analyzer", - "is_processing_suspended", - "is_protocol_analyzer", - "is_remote_event", - "is_tcp_port", - "is_udp_port", - "is_v4_addr", - "is_v4_subnet", - "is_v6_addr", - "is_v6_subnet", - "is_valid_ip", - "join_string_set", - "join_string_vec", - "levenshtein_distance", - "ljust", - "ln", - "load_CPP", - "log10", - "log2", - "lookup_ID", - "lookup_addr", - "lookup_autonomous_system", - "lookup_connection", - "lookup_hostname", - "lookup_hostname_txt", - "lookup_location", - "lstrip", - "mask_addr", - "match_signatures", - "matching_subnets", - "md5_hash", - "md5_hash_finish", - "md5_hash_init", - "md5_hash_update", - "md5_hmac", - "mkdir", - "mmdb_open_asn_db", - "mmdb_open_location_db", - "network_time", - "open", - "open_for_append", - "packet_source", - "paraglob_equals", - "paraglob_init", - "paraglob_match", - "parse_distinguished_name", - "parse_eftp_port", - "parse_ftp_epsv", - "parse_ftp_pasv", - "parse_ftp_port", - "piped_exec", - "port_to_count", - "pow", - "preserve_prefix", - "preserve_subnet", - "print_raw", - "ptr_name_to_addr", - "rand", - "raw_bytes_to_v4_addr", - "raw_bytes_to_v6_addr", - "reading_live_traffic", - "reading_traces", - "record_fields", - "record_type_to_vector", - "remask_addr", - "remove_prefix", - "remove_suffix", - "rename", - "reverse", - "rfind_str", - "rjust", - "rmdir", - "rotate_file", - "rotate_file_by_name", - "routing0_data_to_addrs", - "rstrip", - "safe_shell_quote", - "same_object", - "sct_verify", - "set_buf", - "set_contents_file", - "set_current_conn_bytes_threshold", - "set_current_conn_duration_threshold", - "set_current_conn_packets_threshold", - "set_file_handle", - "set_inactivity_timeout", - "set_keys", - "set_login_state", - "set_network_time", - "set_record_packets", - "set_secret", - "set_ssl_established", - "setenv", - "sha1_hash", - "sha1_hash_finish", - "sha1_hash_init", - "sha1_hash_update", - "sha256_hash", - "sha256_hash_finish", - "sha256_hash_init", - "sha256_hash_update", - "skip_further_processing", - "skip_http_entity_data", - "skip_smtp_data", - "split_string", - "split_string1", - "split_string_all", - "split_string_n", - "sqrt", - "srand", - "starts_with", - "str_smith_waterman", - "str_split_indices", - "strcmp", - "strftime", - "string_cat", - "string_fill", - "string_to_ascii_hex", - "string_to_pattern", - "strip", - "strptime", - "strstr", - "sub", - "sub_bytes", - "subnet_to_addr", - "subnet_width", - "subst_string", - "suspend_processing", - "swap_case", - "syslog", - "system", - "system_env", - "table_keys", - "table_values", - "terminate", - "time_to_double", - "to_addr", - "to_count", - "to_double", - "to_int", - "to_json", - "to_lower", - "to_port", - "to_string_literal", - "to_subnet", - "to_title", - "to_upper", - "topk_add", - "topk_count", - "topk_epsilon", - "topk_get_top", - "topk_init", - "topk_merge", - "topk_merge_prune", - "topk_size", - "topk_sum", - "type_aliases", - "type_name", - "unescape_URI", - "uninstall_dst_addr_filter", - "uninstall_dst_net_filter", - "uninstall_src_addr_filter", - "uninstall_src_net_filter", - "unique_id", - "unique_id_from", - "unlink", - "uuid_to_string", - "val_footprint", - "write_file", - "x509_check_cert_hostname", - "x509_check_hostname", - "x509_from_der", - "x509_get_certificate_string", - "x509_issuer_name_hash", - "x509_ocsp_verify", - "x509_parse", - "x509_set_certificate_cache", - "x509_set_certificate_cache_hit_callback", - "x509_spki_hash", - "x509_subject_name_hash", - "x509_verify", - "zeek_args", - "zeek_is_terminating", - "zeek_version", - "zfill", +// Attributes associated with functions. Currently these are mutually +// exclusive (i.e., no function will have more than one), but for now +// we use a bitmask-style approach so we can accommodate future attributes +// that might overlap. + +// BiF Functions that are not listed are assumed to have Unknown side effects. +// (These are described in comments after the table definition.) Script +// functions that are not listed as assumed to not be "special", i.e. known +// to the event engine. + +// Does not change script-level state (though may change internal state). +#define ATTR_NO_SCRIPT_SIDE_EFFECTS 0x1 + +// Does not change any Zeek state, internal or external. (May change +// state outside of Zeek, such as file system elements.) Implies +// ATTR_NO_SCRIPT_SIDE_EFFECTS. +#define ATTR_NO_ZEEK_SIDE_EFFECTS 0x2 + +// Calls made with the same arguments yield the same results. Implies +// ATTR_NO_ZEEK_SIDE_EFFECTS. +#define ATTR_IDEMPOTENT 0x4 + +// The event engine knows about this script function and may call it +// during its processing. +#define ATTR_SPECIAL_SCRIPT_FUNC 0x8 + +static std::unordered_map func_attrs = { + // Script functions. + {"Analyzer::disabling_analyzer", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Log::__default_rotation_postprocessor", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Log::empty_post_delay_cb", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Log::log_stream_policy", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Log::rotation_format_func", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Supervisor::stderr_hook", ATTR_SPECIAL_SCRIPT_FUNC}, + {"Supervisor::stdout_hook", ATTR_SPECIAL_SCRIPT_FUNC}, + {"assertion_failure", ATTR_SPECIAL_SCRIPT_FUNC}, + {"assertion_result", ATTR_SPECIAL_SCRIPT_FUNC}, + {"discarder_check_icmp", ATTR_SPECIAL_SCRIPT_FUNC}, + {"discarder_check_ip", ATTR_SPECIAL_SCRIPT_FUNC}, + {"discarder_check_tcp", ATTR_SPECIAL_SCRIPT_FUNC}, + {"discarder_check_udp", ATTR_SPECIAL_SCRIPT_FUNC}, + {"from_json_default_key_mapper", ATTR_SPECIAL_SCRIPT_FUNC}, + + // BiFs. + {"Analyzer::__disable_all_analyzers", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Analyzer::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Analyzer::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Analyzer::__has_tag", ATTR_IDEMPOTENT}, + {"Analyzer::__name", ATTR_IDEMPOTENT}, + {"Analyzer::__register_for_port", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Analyzer::__schedule_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Analyzer::__tag", ATTR_IDEMPOTENT}, + {"FileExtract::__set_limit", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__add_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__analyzer_enabled", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Files::__analyzer_name", ATTR_IDEMPOTENT}, + {"Files::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__disable_reassembly", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__enable_reassembly", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__file_exists", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Files::__lookup_file", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Files::__remove_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__set_reassembly_buffer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__set_timeout_interval", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Files::__stop", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Input::__create_analysis_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Input::__create_event_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Input::__create_table_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Input::__force_update", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Input::__remove_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__add_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__create_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__delay_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__disable_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__enable_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__flush", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__get_delay_queue_size", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Log::__remove_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__remove_stream", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__set_buf", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__set_max_delay_interval", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Log::__set_max_delay_queue_size", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Option::any_set_to_any_vec", ATTR_IDEMPOTENT}, + {"Option::set_change_handler", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::GTPV1::remove_gtpv1_connection", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::TEREDO::remove_teredo_connection", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::__disable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::__enable_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::__set_ignore_checksums_nets", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::register_packet_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::register_protocol_detection", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"PacketAnalyzer::try_register_packet_analyzer_by_name", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Pcap::error", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Pcap::findalldevs", ATTR_IDEMPOTENT}, + {"Pcap::get_filter_state", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Pcap::get_filter_state_string", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Pcap::install_pcap_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Pcap::precompile_pcap_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::conn_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::error", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::fatal", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::fatal_error_with_core", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::file_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::flow_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::get_weird_sampling_duration", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Reporter::get_weird_sampling_global_list", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Reporter::get_weird_sampling_rate", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Reporter::get_weird_sampling_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Reporter::get_weird_sampling_whitelist", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Reporter::info", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::net_weird", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::set_weird_sampling_duration", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::set_weird_sampling_global_list", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::set_weird_sampling_rate", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::set_weird_sampling_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::set_weird_sampling_whitelist", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Reporter::warning", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Spicy::__resource_usage", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Spicy::__toggle_analyzer", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Supervisor::__create", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Supervisor::__destroy", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Supervisor::__init_cluster", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Supervisor::__is_supervised", ATTR_IDEMPOTENT}, + {"Supervisor::__is_supervisor", ATTR_IDEMPOTENT}, + {"Supervisor::__node", ATTR_IDEMPOTENT}, + {"Supervisor::__restart", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Supervisor::__status", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"Supervisor::__stem_pid", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__collect_histogram_metrics", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__collect_metrics", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_counter_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_counter_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_counter_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_counter_value", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_gauge_dec", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_gauge_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_gauge_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_gauge_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_gauge_value", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_histogram_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_histogram_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_histogram_observe", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__dbl_histogram_sum", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_counter_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_counter_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_counter_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_counter_value", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_gauge_dec", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_gauge_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_gauge_inc", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_gauge_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_gauge_value", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_histogram_family", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_histogram_metric_get_or_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_histogram_observe", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"Telemetry::__int_histogram_sum", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"__init_primary_bifs", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"__init_secondary_bifs", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"active_file", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"addr_to_counts", ATTR_IDEMPOTENT}, + {"addr_to_ptr_name", ATTR_IDEMPOTENT}, + {"addr_to_subnet", ATTR_IDEMPOTENT}, + {"all_set", ATTR_IDEMPOTENT}, + {"anonymize_addr", ATTR_IDEMPOTENT}, + {"any_set", ATTR_IDEMPOTENT}, + {"backtrace", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bare_mode", ATTR_IDEMPOTENT}, + {"bloomfilter_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_basic_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_basic_init2", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_clear", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_counting_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_decrement", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_internal_state", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_intersect", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_lookup", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bloomfilter_merge", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"bytestring_to_count", ATTR_IDEMPOTENT}, + {"bytestring_to_double", ATTR_IDEMPOTENT}, + {"bytestring_to_float", ATTR_IDEMPOTENT}, + {"bytestring_to_hexstr", ATTR_IDEMPOTENT}, + {"calc_next_rotate", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"cat", ATTR_IDEMPOTENT}, + {"cat_sep", ATTR_IDEMPOTENT}, + {"ceil", ATTR_IDEMPOTENT}, + {"check_subnet", ATTR_IDEMPOTENT}, + {"clean", ATTR_IDEMPOTENT}, + {"close", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"community_id_v1", ATTR_IDEMPOTENT}, + {"compress_path", ATTR_IDEMPOTENT}, + {"connection_exists", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"continue_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"convert_for_pattern", ATTR_IDEMPOTENT}, + {"count_substr", ATTR_IDEMPOTENT}, + {"count_to_double", ATTR_IDEMPOTENT}, + {"count_to_port", ATTR_IDEMPOTENT}, + {"count_to_v4_addr", ATTR_IDEMPOTENT}, + {"counts_to_addr", ATTR_IDEMPOTENT}, + {"current_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"current_event_time", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"current_time", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"decode_base64", ATTR_IDEMPOTENT}, + {"decode_base64_conn", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"decode_netbios_name", ATTR_IDEMPOTENT}, + {"decode_netbios_name_type", ATTR_IDEMPOTENT}, + {"disable_event_group", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"disable_module_events", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"do_profiling", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"double_to_count", ATTR_IDEMPOTENT}, + {"double_to_int", ATTR_IDEMPOTENT}, + {"double_to_interval", ATTR_IDEMPOTENT}, + {"double_to_time", ATTR_IDEMPOTENT}, + {"dump_current_packet", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"dump_packet", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"dump_rule_stats", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"edit", ATTR_IDEMPOTENT}, + {"enable_event_group", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"enable_module_events", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"enable_raw_output", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"encode_base64", ATTR_IDEMPOTENT}, + {"ends_with", ATTR_IDEMPOTENT}, + {"entropy_test_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"entropy_test_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"entropy_test_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"enum_names", ATTR_IDEMPOTENT}, + {"enum_to_int", ATTR_IDEMPOTENT}, + {"escape_string", ATTR_IDEMPOTENT}, + {"exit", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"exp", ATTR_IDEMPOTENT}, + {"file_magic", ATTR_IDEMPOTENT}, + {"file_mode", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"file_size", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"filter_subnet_table", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"find_all", ATTR_IDEMPOTENT}, + {"find_all_ordered", ATTR_IDEMPOTENT}, + {"find_entropy", ATTR_IDEMPOTENT}, + {"find_last", ATTR_IDEMPOTENT}, + {"find_str", ATTR_IDEMPOTENT}, + {"floor", ATTR_IDEMPOTENT}, + {"flush_all", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"fmt", ATTR_IDEMPOTENT}, + {"fmt_ftp_port", ATTR_IDEMPOTENT}, + {"fnv1a32", ATTR_IDEMPOTENT}, + {"generate_all_events", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"get_broker_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_conn_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_conn_transport_proto", ATTR_IDEMPOTENT}, + {"get_contents_file", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_current_conn_bytes_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_current_conn_duration_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_current_conn_packets_threshold", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_current_packet", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_current_packet_header", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_dns_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_event_handler_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_event_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_file_analysis_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_file_name", ATTR_IDEMPOTENT}, + {"get_gap_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_identifier_comments", ATTR_IDEMPOTENT}, + {"get_identifier_declaring_script", ATTR_IDEMPOTENT}, + {"get_login_state", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_matcher_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_net_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_orig_seq", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_package_readme", ATTR_IDEMPOTENT}, + {"get_port_transport_proto", ATTR_IDEMPOTENT}, + {"get_proc_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_reassembler_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_record_field_comments", ATTR_IDEMPOTENT}, + {"get_record_field_declaring_script", ATTR_IDEMPOTENT}, + {"get_reporter_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_resp_seq", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_script_comments", ATTR_IDEMPOTENT}, + {"get_thread_stats", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"get_timer_stats", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"getenv", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"gethostname", ATTR_IDEMPOTENT}, + {"getpid", ATTR_IDEMPOTENT}, + {"global_container_footprints", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"global_ids", ATTR_IDEMPOTENT}, + {"global_options", ATTR_IDEMPOTENT}, + {"gsub", ATTR_IDEMPOTENT}, + {"has_event_group", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"has_module_events", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"have_spicy", ATTR_IDEMPOTENT}, + {"have_spicy_analyzers", ATTR_IDEMPOTENT}, + {"haversine_distance", ATTR_IDEMPOTENT}, + {"hexdump", ATTR_IDEMPOTENT}, + {"hexstr_to_bytestring", ATTR_IDEMPOTENT}, + {"hll_cardinality_add", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"hll_cardinality_copy", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"hll_cardinality_estimate", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"hll_cardinality_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"hll_cardinality_merge_into", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"hrw_weight", ATTR_IDEMPOTENT}, + {"identify_data", ATTR_IDEMPOTENT}, + {"install_dst_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"install_dst_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"install_src_addr_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"install_src_net_filter", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"int_to_count", ATTR_IDEMPOTENT}, + {"int_to_double", ATTR_IDEMPOTENT}, + {"interval_to_double", ATTR_IDEMPOTENT}, + {"is_alnum", ATTR_IDEMPOTENT}, + {"is_alpha", ATTR_IDEMPOTENT}, + {"is_ascii", ATTR_IDEMPOTENT}, + {"is_file_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"is_icmp_port", ATTR_IDEMPOTENT}, + {"is_local_interface", ATTR_IDEMPOTENT}, + {"is_num", ATTR_IDEMPOTENT}, + {"is_packet_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"is_processing_suspended", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"is_protocol_analyzer", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"is_remote_event", ATTR_IDEMPOTENT}, + {"is_tcp_port", ATTR_IDEMPOTENT}, + {"is_udp_port", ATTR_IDEMPOTENT}, + {"is_v4_addr", ATTR_IDEMPOTENT}, + {"is_v4_subnet", ATTR_IDEMPOTENT}, + {"is_v6_addr", ATTR_IDEMPOTENT}, + {"is_v6_subnet", ATTR_IDEMPOTENT}, + {"is_valid_ip", ATTR_IDEMPOTENT}, + {"join_string_set", ATTR_IDEMPOTENT}, + {"join_string_vec", ATTR_IDEMPOTENT}, + {"levenshtein_distance", ATTR_IDEMPOTENT}, + {"ljust", ATTR_IDEMPOTENT}, + {"ln", ATTR_IDEMPOTENT}, + {"load_CPP", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"log10", ATTR_IDEMPOTENT}, + {"log2", ATTR_IDEMPOTENT}, + {"lookup_ID", ATTR_IDEMPOTENT}, + {"lookup_addr", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"lookup_autonomous_system", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"lookup_connection", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"lookup_hostname", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"lookup_hostname_txt", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"lookup_location", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"lstrip", ATTR_IDEMPOTENT}, + {"mask_addr", ATTR_IDEMPOTENT}, + {"match_signatures", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"matching_subnets", ATTR_IDEMPOTENT}, + {"md5_hash", ATTR_IDEMPOTENT}, + {"md5_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"md5_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"md5_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"md5_hmac", ATTR_IDEMPOTENT}, + {"mkdir", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"mmdb_open_asn_db", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"mmdb_open_location_db", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"network_time", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"open", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"open_for_append", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"packet_source", ATTR_IDEMPOTENT}, + {"paraglob_equals", ATTR_IDEMPOTENT}, + {"paraglob_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"paraglob_match", ATTR_IDEMPOTENT}, + {"parse_distinguished_name", ATTR_IDEMPOTENT}, + {"parse_eftp_port", ATTR_IDEMPOTENT}, + {"parse_ftp_epsv", ATTR_IDEMPOTENT}, + {"parse_ftp_pasv", ATTR_IDEMPOTENT}, + {"parse_ftp_port", ATTR_IDEMPOTENT}, + {"piped_exec", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"port_to_count", ATTR_IDEMPOTENT}, + {"pow", ATTR_IDEMPOTENT}, + {"preserve_prefix", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"preserve_subnet", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"print_raw", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"ptr_name_to_addr", ATTR_IDEMPOTENT}, + {"rand", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"raw_bytes_to_v4_addr", ATTR_IDEMPOTENT}, + {"raw_bytes_to_v6_addr", ATTR_IDEMPOTENT}, + {"reading_live_traffic", ATTR_IDEMPOTENT}, + {"reading_traces", ATTR_IDEMPOTENT}, + {"record_fields", ATTR_IDEMPOTENT}, + {"record_type_to_vector", ATTR_IDEMPOTENT}, + {"remask_addr", ATTR_IDEMPOTENT}, + {"remove_prefix", ATTR_IDEMPOTENT}, + {"remove_suffix", ATTR_IDEMPOTENT}, + {"rename", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"reverse", ATTR_IDEMPOTENT}, + {"rfind_str", ATTR_IDEMPOTENT}, + {"rjust", ATTR_IDEMPOTENT}, + {"rmdir", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"rotate_file", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"rotate_file_by_name", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"routing0_data_to_addrs", ATTR_IDEMPOTENT}, + {"rstrip", ATTR_IDEMPOTENT}, + {"safe_shell_quote", ATTR_IDEMPOTENT}, + {"same_object", ATTR_IDEMPOTENT}, + {"sct_verify", ATTR_IDEMPOTENT}, + {"set_buf", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_contents_file", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_current_conn_bytes_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_current_conn_duration_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_current_conn_packets_threshold", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_file_handle", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_inactivity_timeout", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_keys", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_login_state", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_network_time", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_record_packets", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_secret", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"set_ssl_established", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"setenv", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha1_hash", ATTR_IDEMPOTENT}, + {"sha1_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha1_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha1_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha256_hash", ATTR_IDEMPOTENT}, + {"sha256_hash_finish", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha256_hash_init", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"sha256_hash_update", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"skip_further_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"skip_http_entity_data", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"skip_smtp_data", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"split_string", ATTR_IDEMPOTENT}, + {"split_string1", ATTR_IDEMPOTENT}, + {"split_string_all", ATTR_IDEMPOTENT}, + {"split_string_n", ATTR_IDEMPOTENT}, + {"sqrt", ATTR_IDEMPOTENT}, + {"srand", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"starts_with", ATTR_IDEMPOTENT}, + {"str_smith_waterman", ATTR_IDEMPOTENT}, + {"str_split_indices", ATTR_IDEMPOTENT}, + {"strcmp", ATTR_IDEMPOTENT}, + {"strftime", ATTR_IDEMPOTENT}, + {"string_cat", ATTR_IDEMPOTENT}, + {"string_fill", ATTR_IDEMPOTENT}, + {"string_to_ascii_hex", ATTR_IDEMPOTENT}, + {"string_to_pattern", ATTR_IDEMPOTENT}, + {"strip", ATTR_IDEMPOTENT}, + {"strptime", ATTR_IDEMPOTENT}, + {"strstr", ATTR_IDEMPOTENT}, + {"sub", ATTR_IDEMPOTENT}, + {"sub_bytes", ATTR_IDEMPOTENT}, + {"subnet_to_addr", ATTR_IDEMPOTENT}, + {"subnet_width", ATTR_IDEMPOTENT}, + {"subst_string", ATTR_IDEMPOTENT}, + {"suspend_processing", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"swap_case", ATTR_IDEMPOTENT}, + {"syslog", ATTR_NO_ZEEK_SIDE_EFFECTS}, + {"system", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"system_env", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"table_keys", ATTR_IDEMPOTENT}, + {"table_pattern_matcher_stats", ATTR_IDEMPOTENT}, + {"table_values", ATTR_IDEMPOTENT}, + {"terminate", ATTR_NO_SCRIPT_SIDE_EFFECTS}, + {"time_to_double", ATTR_IDEMPOTENT}, + {"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: @@ -472,6 +518,9 @@ static std::unordered_set side_effects_free_BiFs = { // Cluster::publish_rr // These call script functions to get topic names. // +// Log::__delay +// Can invoke a callback function specified at run-time. +// // Log::__write // Calls log policy functions. // @@ -501,6 +550,22 @@ static std::unordered_set side_effects_free_BiFs = { // 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. -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 diff --git a/src/script_opt/FuncInfo.h b/src/script_opt/FuncInfo.h index a7925619ae..f4bf333cc0 100644 --- a/src/script_opt/FuncInfo.h +++ b/src/script_opt/FuncInfo.h @@ -1,10 +1,6 @@ // See the file "COPYING" in the main distribution directory for copyright. -// Utility functions that return information about Zeek functions. Currently -// 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. +// Utility functions that return information about Zeek functions. #pragma once @@ -12,6 +8,17 @@ 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 diff --git a/src/script_opt/Inline.cc b/src/script_opt/Inline.cc index ff45a56b25..56d71ba366 100644 --- a/src/script_opt/Inline.cc +++ b/src/script_opt/Inline.cc @@ -5,6 +5,7 @@ #include "zeek/Desc.h" #include "zeek/EventRegistry.h" #include "zeek/module_util.h" +#include "zeek/script_opt/FuncInfo.h" #include "zeek/script_opt/ProfileFunc.h" #include "zeek/script_opt/ScriptOpt.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 // directly calls. 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 cs; // Aspirational .... @@ -40,6 +51,32 @@ void Inliner::Analyze() { } 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(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 @@ -332,8 +369,6 @@ ExprPtr Inliner::CheckForInlining(CallExprPtr c) { auto scope = func_vf->GetScope(); auto ie = DoInline(func_vf, body, c->ArgsPtr(), scope, ia->second); - printf("inlined %s\n", obj_desc(c.get()).c_str()); - if ( ie ) { ie->SetOriginal(c); did_inline.insert(func_vf.get()); diff --git a/src/script_opt/ProfileFunc.cc b/src/script_opt/ProfileFunc.cc index 9d13e94812..0457482703 100644 --- a/src/script_opt/ProfileFunc.cc +++ b/src/script_opt/ProfileFunc.cc @@ -193,22 +193,21 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { all_globals.insert(id); const auto& t = id->GetType(); - if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT ) - events.insert(id->Name()); + if ( t->Tag() == TYPE_FUNC ) + if ( t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT ) + events.insert(id->Name()); break; } - // This is a tad ugly. Unfortunately due to the - // weird way that Zeek function *declarations* work, - // there's no reliable way to get the list of - // parameters for a function *definition*, since - // they can have different names than what's present - // in the declaration. So we identify them directly, - // by knowing that they come at the beginning of the - // frame ... and being careful to avoid misconfusing - // a lambda capture with a low frame offset as a - // parameter. + // This is a tad ugly. Unfortunately due to the weird way + // that Zeek function *declarations* work, there's no reliable + // way to get the list of parameters for a function *definition*, + // since they can have different names than what's present in the + // declaration. So we identify them directly, by knowing that + // they come at the beginning of the frame ... and being careful + // to avoid misconfusing a lambda capture with a low frame offset + // as a parameter. if ( captures.count(id) == 0 && id->Offset() < num_params ) params.insert(id); @@ -251,11 +250,25 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { case EXPR_REMOVE_FROM: case EXPR_ASSIGN: { 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 ) lhs = lhs->GetOp1(); - else if ( e->Tag() == EXPR_ASSIGN ) + else if ( is_assign ) // This isn't a direct assignment, but instead an overloaded // use of "=" such as in a table constructor. break; @@ -267,7 +280,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { auto id = lhs->AsNameExpr()->Id(); TrackAssignment(id); - if ( e->Tag() == EXPR_ASSIGN ) { + if ( is_assign ) { auto a_e = static_cast(e); auto& av = a_e->AssignVal(); if ( av ) @@ -287,7 +300,7 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { // assignment "a[b] = aggr", it's not a[b]'s type but // rather a's type. However, for any of the others, // 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()); else aggr_mods.insert(lhs_t.get()); @@ -325,20 +338,39 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { case EXPR_CALL: { auto c = e->AsCallExpr(); + auto args = c->Args(); 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; + } + else does_indirect_calls = true; - return TC_CONTINUE; + + // 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(); - auto func = n->Id(); - - if ( ! func->IsGlobal() ) { - does_indirect_calls = true; + if ( does_indirect_calls ) + // We waited on doing this until after checking for + // indirect functions. return TC_CONTINUE; - } all_globals.insert(func); @@ -361,7 +393,6 @@ TraversalCode ProfileFunc::PreExpr(const Expr* e) { } // Recurse into the arguments. - auto args = c->Args(); args->Traverse(this); // 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(); if ( func->GetKind() == Func::BUILTIN_FUNC ) { - if ( ! is_side_effect_free(func->Name()) ) + if ( ! has_no_script_side_effects(func->Name()) ) is_unknown = true; return true; } @@ -1137,7 +1168,7 @@ bool ProfileFuncs::DefinitelyHasNoSideEffects(const ExprPtr& e) const { return false; for ( auto& b : pf->BiFGlobals() ) - if ( ! is_side_effect_free(b->Name()) ) + if ( ! has_no_script_side_effects(b->Name()) ) return false; return true; @@ -1228,7 +1259,7 @@ bool ProfileFuncs::AssessSideEffects(const ProfileFunc* pf, IDSet& non_local_ids } for ( auto& b : pf->BiFGlobals() ) - if ( ! is_side_effect_free(b->Name()) ) { + if ( ! has_no_script_side_effects(b->Name()) ) { is_unknown = true; return true; } diff --git a/src/script_opt/ProfileFunc.h b/src/script_opt/ProfileFunc.h index 27c68a215c..55814a9686 100644 --- a/src/script_opt/ProfileFunc.h +++ b/src/script_opt/ProfileFunc.h @@ -120,6 +120,7 @@ public: const std::unordered_set& TypeSwitches() const { return type_switches; } bool DoesIndirectCalls() const { return does_indirect_calls; } + const IDSet& IndirectFuncs() const { return indirect_funcs; } int NumParams() const { return num_params; } int NumLambdas() const { return lambdas.size(); } @@ -271,6 +272,11 @@ protected: // than simply a function's (global) name. 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 // into its hash. std::vector addl_hashes; diff --git a/src/script_opt/ZAM/maint/BiFs.list b/src/script_opt/ZAM/maint/BiFs.list index d07fcb33b5..a1e0c8190a 100644 --- a/src/script_opt/ZAM/maint/BiFs.list +++ b/src/script_opt/ZAM/maint/BiFs.list @@ -113,12 +113,17 @@ Input::__force_update Input::__remove_stream Log::__add_filter Log::__create_stream +Log::__delay +Log::__delay_finish Log::__disable_stream Log::__enable_stream Log::__flush +Log::__get_delay_queue_size Log::__remove_filter Log::__remove_stream Log::__set_buf +Log::__set_max_delay_interval +Log::__set_max_delay_queue_size Log::__write Option::any_set_to_any_vec Option::set @@ -489,6 +494,7 @@ syslog system system_env table_keys +table_pattern_matcher_stats table_values terminate time_to_double