File 0003-Fix-infinite-recursion-if-component-has-itself-liste.patch of Package AppStream

From 823d7065ffcaec57bdbef479dce49ae97ff08640 Mon Sep 17 00:00:00 2001
From: Matthias Klumpp <matthias@tenstral.net>
Date: Tue, 30 Jul 2019 02:38:47 +0200
Subject: [PATCH 3/3] Fix infinite recursion if component has itself listed as
 an addon

This particular case of a component being an addon to itself is
nonsense, but people may make that mistake and we shouldn't crash in
that case.
With this patch the cache will be resilient against such cases and
simply ignore components depending on themselves.
We could still get nasty dependency loops though, with A depending on B
depending on A. This is a bit more complicated to resolve and will be
fixed in a future commit.
Resolves: #243
---
 src/as-cache.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/as-cache.c b/src/as-cache.c
index 50b42193..3afabda7 100644
--- a/src/as-cache.c
+++ b/src/as-cache.c
@@ -1573,7 +1573,7 @@ as_cache_register_addons_for_component (AsCache *cache, MDB_txn *txn, AsComponen
 {
 	AsCachePrivate *priv = GET_PRIVATE (cache);
 	MDB_val dval;
-	g_autoptr(GPtrArray) addons = NULL;
+	g_autofree guint8 *cpt_checksum = NULL;
 	GError *tmp_error = NULL;
 
 	dval = as_cache_txn_get_value (cache,
@@ -1588,14 +1588,29 @@ as_cache_register_addons_for_component (AsCache *cache, MDB_txn *txn, AsComponen
 	if (dval.mv_size == 0)
 		return TRUE;
 
-	addons = as_cache_components_by_hash_list (cache, txn, dval.mv_data, dval.mv_size, &tmp_error);
-	if (addons == NULL) {
-		g_propagate_error (error, tmp_error);
-		return FALSE;
-	}
+	/* retrieve cache checksum of this component */
+	as_generate_cache_checksum (as_component_get_data_id (cpt),
+				    -1,
+				    &cpt_checksum,
+				    NULL);
+
+	g_assert_cmpint (dval.mv_size % AS_CACHE_CHECKSUM_LEN, ==, 0);
+	for (gsize i = 0; i < dval.mv_size; i += AS_CACHE_CHECKSUM_LEN) {
+		const guint8 *chash = dval.mv_data + i;
+		AsComponent *addon;
+
+		/* ignore addon that extends itself to prevent infinite recursion */
+		if (memcmp (chash, cpt_checksum, AS_CACHE_CHECKSUM_LEN) == 0)
+			continue;
 
-	for (guint i = 0; i < addons->len; i++)
-		as_component_add_addon (cpt, AS_COMPONENT (g_ptr_array_index (addons, i)));
+		addon = as_cache_component_by_hash (cache, txn, chash, &tmp_error);
+		if (tmp_error != NULL) {
+			g_propagate_prefixed_error (error, tmp_error, "Failed to retrieve addon component data: ");
+			return FALSE;
+		}
+		if (addon != NULL)
+			as_component_add_addon (cpt, addon);
+	}
 
 	return TRUE;
 }
-- 
2.22.0