From 2b9b3118549bc3251a5c340cc1d471af513fdc88 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 11 Oct 2020 18:33:44 +0200 Subject: libtracker-data: Process Update rule iteratively The Update rule is defined upon itself, we interpret this a bit too literally, and do the same thing when interpreting the parse tree. This makes the maximum stack size an indirect factor that limits how big a series of updates can possibly be. (e.g. the array at tracker_sparql_connection_update_array_async) This is obviously bad, so process the updates iteratively, this will avoid hitting stack limits by just concatenating legit updates together. Fixes: https://gitlab.gnome.org/GNOME/tracker-miners/-/issues/91 --- src/libtracker-data/tracker-sparql.c | 45 ++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c index 2ff43d045..34571e131 100644 --- a/src/libtracker-data/tracker-sparql.c +++ b/src/libtracker-data/tracker-sparql.c @@ -2538,32 +2538,47 @@ static gboolean translate_Update (TrackerSparql *sparql, GError **error) { + gboolean cont = TRUE; + /* Update ::= Prologue ( Update1 ( ';' Update )? )? * * TRACKER EXTENSION: * ';' separator is made optional. + * + * Note: Even though the rule is defined recursively, we + * process it iteratively here. This is in order to avoid + * making maximum update buffer depend on stack size. */ - _call_rule (sparql, NAMED_RULE_Prologue, error); + while (cont) { + _call_rule (sparql, NAMED_RULE_Prologue, error); - if (!sparql->current_state->blank_node_map) { - sparql->current_state->blank_node_map = - g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - } + if (!sparql->current_state->blank_node_map) { + sparql->current_state->blank_node_map = + g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + } - if (_check_in_rule (sparql, NAMED_RULE_Update1)) { - if (sparql->blank_nodes) - g_variant_builder_open (sparql->blank_nodes, G_VARIANT_TYPE ("aa{ss}")); + if (_check_in_rule (sparql, NAMED_RULE_Update1)) { + if (sparql->blank_nodes) + g_variant_builder_open (sparql->blank_nodes, G_VARIANT_TYPE ("aa{ss}")); - _call_rule (sparql, NAMED_RULE_Update1, error); + _call_rule (sparql, NAMED_RULE_Update1, error); - if (sparql->blank_nodes) - g_variant_builder_close (sparql->blank_nodes); + if (sparql->blank_nodes) + g_variant_builder_close (sparql->blank_nodes); - _optional (sparql, RULE_TYPE_LITERAL, LITERAL_SEMICOLON); + _optional (sparql, RULE_TYPE_LITERAL, LITERAL_SEMICOLON); - if (_check_in_rule (sparql, NAMED_RULE_Update)) - _call_rule (sparql, NAMED_RULE_Update, error); + if (_check_in_rule (sparql, NAMED_RULE_Update)) { + /* Handle the rule inline in the next iteration */ + tracker_sparql_iter_next (sparql); + cont = TRUE; + } else { + cont = FALSE; + } + } else { + cont = FALSE; + } } return TRUE; -- cgit v1.2.1