From ba68a8a3788a7f3ff3945abd03459a1af909ab46 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 4 Feb 2015 09:23:52 +0000 Subject: Fix a crash when more than one thread tries to ensure the same package This can happen when a package is itself an extra package of another, at the same time being a valid application itself. This is probably a packaging bug, but crashing isn't nice either. --- libappstream-builder/asb-package.c | 22 ++++++++++++++++++---- libappstream-builder/asb-self-test.c | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) (limited to 'libappstream-builder') diff --git a/libappstream-builder/asb-package.c b/libappstream-builder/asb-package.c index d0e9d4f..7ca89c4 100644 --- a/libappstream-builder/asb-package.c +++ b/libappstream-builder/asb-package.c @@ -42,7 +42,9 @@ struct _AsbPackagePrivate gboolean enabled; gboolean is_open; gchar **filelist; + guint filelist_refcount; GPtrArray *deps; + guint deps_refcount; gchar *filename; gchar *basename; gchar *name; @@ -966,6 +968,12 @@ asb_package_ensure (AsbPackage *pkg, return FALSE; } + /* this is recounted */ + if (flags & ASB_PACKAGE_ENSURE_DEPS) + priv->deps_refcount++; + if (flags & ASB_PACKAGE_ENSURE_FILES) + priv->filelist_refcount++; + /* clear flags */ if (priv->name != NULL) flags &= ~ASB_PACKAGE_ENSURE_NEVRA; @@ -1007,11 +1015,17 @@ void asb_package_clear (AsbPackage *pkg, AsbPackageEnsureFlags flags) { AsbPackagePrivate *priv = GET_PRIVATE (pkg); - if (flags & ASB_PACKAGE_ENSURE_DEPS) - g_ptr_array_set_size (priv->deps, 0); + + /* this is recounted */ + if (flags & ASB_PACKAGE_ENSURE_DEPS) { + if (priv->deps_refcount > 0 && --priv->deps_refcount == 0) + g_ptr_array_set_size (priv->deps, 0); + } if (flags & ASB_PACKAGE_ENSURE_FILES) { - g_strfreev (priv->filelist); - priv->filelist = NULL; + if (priv->filelist_refcount > 0 && --priv->filelist_refcount == 0) { + g_strfreev (priv->filelist); + priv->filelist = NULL; + } } } diff --git a/libappstream-builder/asb-self-test.c b/libappstream-builder/asb-self-test.c index b196cba..687bb21 100644 --- a/libappstream-builder/asb-self-test.c +++ b/libappstream-builder/asb-self-test.c @@ -155,6 +155,29 @@ asb_test_package_rpm_func (void) asb_package_set_config (pkg, "test", "dave2"); g_assert_cmpstr (asb_package_get_config (pkg, "test"), ==, "dave2"); + /* clear */ + asb_package_clear (pkg, + ASB_PACKAGE_ENSURE_DEPS | + ASB_PACKAGE_ENSURE_FILES); + g_assert (asb_package_get_filelist (pkg) == NULL); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 0); + + /* clear, ensure, ensure, clear, check, clear */ + asb_package_clear (pkg, ASB_PACKAGE_ENSURE_DEPS); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 0); + ret = asb_package_ensure (pkg, ASB_PACKAGE_ENSURE_DEPS, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 3); + ret = asb_package_ensure (pkg, ASB_PACKAGE_ENSURE_DEPS, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 3); + asb_package_clear (pkg, ASB_PACKAGE_ENSURE_DEPS); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 3); + asb_package_clear (pkg, ASB_PACKAGE_ENSURE_DEPS); + g_assert_cmpint (asb_package_get_deps(pkg)->len, ==, 0); + /* compare */ g_assert_cmpint (asb_package_compare (pkg, pkg), ==, 0); -- cgit v1.2.1