]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
fts-flatcurve: Fix potential crash when searching virtual mailboxes
authorMichael M Slusarz <michael.slusarz@open-xchange.com>
Wed, 13 Mar 2024 00:20:24 +0000 (18:20 -0600)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Thu, 20 Feb 2025 13:57:08 +0000 (13:57 +0000)
Fixes:
Panic: file fts-search.c: line 87 (level_scores_add_vuids):
assertion failed: (array_count(&vuids_arr) == array_count(&br->scores))

src/plugins/fts-flatcurve/fts-backend-flatcurve-xapian.cc

index fb90237d100698a331ea647439d422d55aa64b8f..aa69bc767fecacea0259c0e1ab8c6daa2ad40018 100644 (file)
@@ -212,8 +212,9 @@ struct fts_flatcurve_xapian_query_iter {
        Xapian::Database *db;
        Xapian::Enquire *enquire;
        Xapian::MSetIterator mset_iter;
-       int curr_query;
-       bool next_query:1;
+       Xapian::MSet m;
+       bool init:1;
+       bool main_query:1;
 };
 
 static int
@@ -2175,8 +2176,8 @@ fts_flatcurve_xapian_query_iter_init(struct flatcurve_fts_query *query)
 {
        struct fts_flatcurve_xapian_query_iter *iter;
        iter = new fts_flatcurve_xapian_query_iter();
-       iter->curr_query = -1;
-       iter->next_query = TRUE;
+       iter->init = FALSE;
+       iter->main_query = TRUE;
        iter->query = query;
        iter->result = p_new(query->pool,
                             struct fts_flatcurve_xapian_query_result, 1);
@@ -2193,26 +2194,30 @@ fts_flatcurve_xapian_query_iter_next(struct fts_flatcurve_xapian_query_iter *ite
        if (iter->error != NULL)
                return FALSE;
 
-       Xapian::MSet m;
-       Xapian::Query *q = NULL;
-       if (iter->next_query) {
-               iter->next_query = FALSE;
+       if (!iter->init) {
+               iter->init = TRUE;
 
-               if (iter->curr_query == -1) {
+               Xapian::Query *q = NULL, maybe;
+               if (iter->main_query) {
                        if (iter->query->xapian->query == NULL)
-                               ++iter->curr_query;
+                               iter->main_query = FALSE;
                        else
                                q = iter->query->xapian->query;
                }
 
                /* Maybe queries. */
-               if ((iter->curr_query >= 0) &&
-                   (array_not_empty(&iter->query->xapian->maybe_queries)) &&
-                   (array_count(&iter->query->xapian->maybe_queries) > iter->curr_query)) {
+               if (!iter->main_query &&
+                   array_not_empty(&iter->query->xapian->maybe_queries)) {
                        const struct flatcurve_fts_query_xapian_maybe *mquery;
-                       mquery = array_idx(&iter->query->xapian->maybe_queries,
-                                                          iter->curr_query);
-                       q = mquery->query;
+                       maybe = Xapian::Query();
+                       array_foreach(&iter->query->xapian->maybe_queries, mquery)
+                               maybe = Xapian::Query(Xapian::Query::OP_OR, maybe,
+                                                     *mquery->query);
+                       /* Add main query to merge Xapian scores correctly. */
+                       if (iter->query->xapian->query != NULL)
+                               maybe = Xapian::Query(Xapian::Query::OP_AND_MAYBE, maybe,
+                                                     *iter->query->xapian->query);
+                       q = &maybe;
                }
 
                if (q == NULL)
@@ -2235,7 +2240,7 @@ fts_flatcurve_xapian_query_iter_next(struct fts_flatcurve_xapian_query_iter *ite
                iter->enquire->set_query(*q);
 
                try {
-                       m = iter->enquire->get_mset(0, iter->db->get_doccount());
+                       iter->m = iter->enquire->get_mset(0, iter->db->get_doccount());
                } catch (Xapian::DatabaseModifiedError &e) {
                        /* Per documentation, this is only thrown if more than
                         * one change has been made to the database. To
@@ -2249,16 +2254,17 @@ fts_flatcurve_xapian_query_iter_next(struct fts_flatcurve_xapian_query_iter *ite
                        i_unreached();
                }
 
-               iter->mset_iter = m.begin();
+               iter->mset_iter = iter->m.begin();
        }
 
-       if (iter->mset_iter == m.end()) {
-               ++iter->curr_query;
-               iter->next_query = TRUE;
+       if (iter->mset_iter == iter->m.end()) {
+               if (!iter->main_query)
+                       return FALSE;
+               iter->init = iter->main_query = FALSE;
                return fts_flatcurve_xapian_query_iter_next(iter, result_r);
        }
 
-       iter->result->maybe = (iter->curr_query >= 0);
+       iter->result->maybe = !iter->main_query;
        iter->result->score = iter->mset_iter.get_weight();
        /* MSet docid can be an "interleaved" docid generated by
         * Xapian::Database when handling multiple DBs at once. Instead, we
@@ -2304,13 +2310,18 @@ int fts_flatcurve_xapian_run_query(struct flatcurve_fts_query *query,
 
        iter = fts_flatcurve_xapian_query_iter_init(query);
        while (fts_flatcurve_xapian_query_iter_next(iter, &result)) {
-               if (result->maybe || query->xapian->maybe)
+               bool add_score = TRUE;
+               if (result->maybe || query->xapian->maybe) {
+                       add_score = !seq_range_exists(&r->uids, result->uid) &&
+                                   !seq_range_exists(&r->maybe_uids, result->uid);
                        seq_range_array_add(&r->maybe_uids, result->uid);
-               else
+               else
                        seq_range_array_add(&r->uids, result->uid);
-               score = array_append_space(&r->scores);
-               score->score = (float)result->score;
-               score->uid = result->uid;
+               if (add_score) {
+                       score = array_append_space(&r->scores);
+                       score->score = (float)result->score;
+                       score->uid = result->uid;
+               }
        }
        return fts_flatcurve_xapian_query_iter_deinit(&iter, error_r);
 }