From: Alexander Moisseev Date: Fri, 8 May 2026 19:18:01 +0000 (+0300) Subject: [Minor] Refactor fuzzy flag collision detection into parse-time check X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c78632a2a03962691760a0c43bdedea45bce36ec;p=thirdparty%2Frspamd.git [Minor] Refactor fuzzy flag collision detection into parse-time check --- diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c index 50f6d49d48..7dbf786b9a 100644 --- a/src/plugins/fuzzy_check.c +++ b/src/plugins/fuzzy_check.c @@ -162,6 +162,7 @@ struct fuzzy_ctx { int cleanup_rules_ref; uint32_t retransmits; gboolean enabled; + GHashTable *writable_flags; /* flag -> rule_name, for collision detection */ }; static inline uint8_t @@ -2274,6 +2275,30 @@ fuzzy_parse_rule(struct rspamd_config *cfg, const ucl_object_t *obj, rspamd_mempool_add_destructor(cfg->cfg_pool, fuzzy_free_rule, rule); + if (rule->mode != fuzzy_rule_read_only && fuzzy_module_ctx->writable_flags != NULL) { + GHashTableIter fit; + gpointer fk, fv; + g_hash_table_iter_init(&fit, rule->mappings); + + while (g_hash_table_iter_next(&fit, &fk, &fv)) { + const char *existing = g_hash_table_lookup(fuzzy_module_ctx->writable_flags, fk); + + if (existing != NULL) { + msg_warn_config( + "fuzzy flag %d is used by both writable rules '%s' and '%s'; " + "write operations will be sent to all matching rules — " + "use unique flags or set `read_only = true` on rules that should not receive writes", + GPOINTER_TO_INT(fk), + existing, + rule->name ? rule->name : "(unnamed)"); + } + else { + g_hash_table_insert(fuzzy_module_ctx->writable_flags, fk, + (gpointer) (rule->name ? rule->name : "(unnamed)")); + } + } + } + return 0; } @@ -2886,6 +2911,11 @@ int fuzzy_check_module_config(struct rspamd_config *cfg, bool validate) 1, 1); + fuzzy_module_ctx->writable_flags = g_hash_table_new(g_direct_hash, g_direct_equal); + rspamd_mempool_add_destructor(cfg->cfg_pool, + (rspamd_mempool_destruct_t) g_hash_table_unref, + fuzzy_module_ctx->writable_flags); + /* * Here we can have 2 possibilities: * @@ -2944,44 +2974,6 @@ int fuzzy_check_module_config(struct rspamd_config *cfg, bool validate) msg_info_config("init internal fuzzy_check module, %d rules loaded", nrules); - /* Check for flag collisions across writable rules */ - if (fuzzy_module_ctx->fuzzy_rules != NULL && fuzzy_module_ctx->fuzzy_rules->len > 1) { - GHashTable *writable_flag_rules = g_hash_table_new(g_direct_hash, g_direct_equal); - unsigned int ri; - struct fuzzy_rule *wrule; - - PTR_ARRAY_FOREACH(fuzzy_module_ctx->fuzzy_rules, ri, wrule) - { - if (wrule->mode == fuzzy_rule_read_only) { - continue; - } - - GHashTableIter flag_it; - gpointer fk, fv; - g_hash_table_iter_init(&flag_it, wrule->mappings); - - while (g_hash_table_iter_next(&flag_it, &fk, &fv)) { - const char *existing_rule_name = g_hash_table_lookup(writable_flag_rules, fk); - - if (existing_rule_name != NULL) { - msg_warn_config( - "fuzzy flag %d is used by both writable rules '%s' and '%s'; " - "write operations will be sent to all matching rules — " - "use unique flags or set `read_only = true` on rules that should not receive writes", - GPOINTER_TO_INT(fk), - existing_rule_name, - wrule->name ? wrule->name : "(unnamed)"); - } - else { - g_hash_table_insert(writable_flag_rules, fk, - (gpointer) (wrule->name ? wrule->name : "(unnamed)")); - } - } - } - - g_hash_table_destroy(writable_flag_rules); - } - /* Register global methods */ lua_getglobal(L, "rspamd_plugins");