From: Vsevolod Stakhov Date: Wed, 26 Nov 2025 09:18:26 +0000 (+0000) Subject: [Fix] Improve atom polarity detection in composites inverted index X-Git-Tag: 3.14.1~5^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f3585335a3d4c08e65fa48641f9be7bee260403;p=thirdparty%2Frspamd.git [Fix] Improve atom polarity detection in composites inverted index Count NOT operations from atom to root instead of just checking direct parent. This correctly handles nested negations like !(A & B) where atoms A and B are both under negation even though their direct parent is AND, not NOT. - Even number of NOTs = positive atom (must be true) - Odd number of NOTs = negative atom (must be false) --- diff --git a/src/libserver/composites/composites_manager.cxx b/src/libserver/composites/composites_manager.cxx index 57ae175cfb..5e3be78d5a 100644 --- a/src/libserver/composites/composites_manager.cxx +++ b/src/libserver/composites/composites_manager.cxx @@ -479,13 +479,35 @@ struct inverted_index_cbdata { bool has_positive; }; +/* + * Count NOT operations from atom to root to determine atom polarity. + * Even number of NOTs = positive atom (must be true for expression to be true) + * Odd number of NOTs = negative atom (must be false for expression to be true) + */ +static bool +atom_is_negated(GNode *atom_node) +{ + int not_count = 0; + GNode *node = atom_node->parent; + + while (node != nullptr) { + if (rspamd_expression_node_is_op(node, OP_NOT)) { + not_count++; + } + node = node->parent; + } + + /* Odd number of NOTs means atom is negated */ + return (not_count & 1) != 0; +} + static void inverted_index_atom_callback(GNode *atom_node, rspamd_expression_atom_t *atom, gpointer ud) { auto *cbd = reinterpret_cast(ud); - /* Check if this atom is under NOT operation */ - if (atom_node->parent && rspamd_expression_node_is_op(atom_node->parent, OP_NOT)) { + /* Check atom polarity by counting NOTs to root */ + if (atom_is_negated(atom_node)) { /* Negated atom - don't add to inverted index */ return; }