]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] Symcache: make FINE propagation deterministic (#5825)
authorVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 7 Jan 2026 14:36:20 +0000 (14:36 +0000)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Wed, 7 Jan 2026 14:36:20 +0000 (14:36 +0000)
src/libserver/symcache/symcache_impl.cxx

index aae779375985c1c52614edd3d95f65148f067c38..44b7a4bab14b08d3a189fafc80d2275051b90868 100644 (file)
@@ -956,22 +956,40 @@ auto symcache::validate(bool strict) -> bool
                                        parent->priority = MAX(p1, p2);
                                        item->priority = parent->priority;
                                }
+                       }
+               }
+
+               total_weight += fabs(item->st->weight);
+       }
+
+       /*
+        * Propagate SYMBOL_TYPE_FINE between virtual symbols and their parents until a fixed point.
+        * This avoids order-dependent results when iterating items_by_symbol.
+        */
+       bool fine_changed;
+       do {
+               fine_changed = false;
+               for (auto &pair: items_by_symbol) {
+                       auto &item = pair.second;
+                       if (item->is_virtual() && !(item->flags & SYMBOL_TYPE_GHOST)) {
+                               auto *parent = const_cast<cache_item *>(item->get_parent(*this));
+
+                               if (parent == nullptr) {
+                                       item->resolve_parent(*this);
+                                       parent = const_cast<cache_item *>(item->get_parent(*this));
+                               }
 
-                               /*
-                                * Sync SYMBOL_TYPE_FINE between virtual symbol and parent.
-                                * If either has negative weight and is marked FINE, propagate to both.
-                                */
                                if ((item->flags & SYMBOL_TYPE_FINE) && !(parent->flags & SYMBOL_TYPE_FINE)) {
                                        parent->flags |= SYMBOL_TYPE_FINE;
+                                       fine_changed = true;
                                }
                                else if ((parent->flags & SYMBOL_TYPE_FINE) && !(item->flags & SYMBOL_TYPE_FINE)) {
                                        item->flags |= SYMBOL_TYPE_FINE;
+                                       fine_changed = true;
                                }
                        }
                }
-
-               total_weight += fabs(item->st->weight);
-       }
+       } while (fine_changed);
 
        /* Now check each metric item and find corresponding symbol in a cache */
        auto ret = true;