summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-02-04 09:23:52 +0000
committerRichard Hughes <richard@hughsie.com>2015-02-04 09:23:54 +0000
commitba68a8a3788a7f3ff3945abd03459a1af909ab46 (patch)
tree113db1a2fa04fb5a803536b101fac40c216db290
parenteb7992290c39efed28179efa9b3a607f9d3637ed (diff)
downloadappstream-glib-ba68a8a3788a7f3ff3945abd03459a1af909ab46.tar.gz
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.
-rw-r--r--libappstream-builder/asb-package.c22
-rw-r--r--libappstream-builder/asb-self-test.c23
2 files changed, 41 insertions, 4 deletions
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);