Compare commits

...

24 Commits

Author SHA1 Message Date
Dylan Baker 116e367525 main: unref another pkg 2022-08-02 11:59:55 -07:00
Dylan Baker dbc8d248c7 cache: use pkgconf_cache_remove to empty the cache
Which ensures that memory handling is done correctly.
2022-08-02 11:59:46 -07:00
Dylan Baker 62608dfe02 queue: don't flatten nothing
If after removing duplicates there are no deps to flatten, return early.
2022-08-02 11:51:59 -07:00
Dylan Baker 02710ffdef cache: if the cache_table is NULL don't search it 2022-08-02 11:51:37 -07:00
Dylan Baker 9d82962160 fixup! cache: set the cache_table to NULL if empty 2022-08-02 11:51:29 -07:00
Dylan Baker 0c72b7cd41 ci: run meson test with the address sanitizer enabled
Set the ASAN_OPTION so that the exitcode is not 1, this avoids asan
returning the exitcode that the tests already expect from a normal
pkgconf error
2022-08-02 09:58:56 -07:00
Dylan Baker c7b0f86815 cache: set the cache_table to NULL if empty
Instead of realloc'ing to a size of 0, set the cache_table to NULL when
removing the last element from it.
2022-08-02 09:58:56 -07:00
Dylan Baker d23dc2c183 cache: don't try to remove packages from the cache if it's NULL
Otherwise we end up reallocing the cache_table, when we shouldn't
2022-08-02 09:58:56 -07:00
Dylan Baker a620e62286 cache: unref the package when removing it from the cache 2022-08-02 09:58:56 -07:00
Dylan Baker 36acd2e409 queue: don't collect static dependencies unless that's what we're looking for
Currently the required_private field gets walked twice, once when the
main required field is walked, and a second time when it is walked
itself. This results in the requires_private field leaking memory.
2022-08-02 09:58:06 -07:00
Dylan Baker 7b3346206e dependency: unref dependency parent if it's set
libpkgconf never sets this internally, but it is in the API and someone
could set it (or libpkgconf could in the future), so let's clean up
after ourselves.
2022-08-02 09:58:06 -07:00
Dylan Baker 75a5fe0757 queue: ensure pkgconf_queue_apply alies cleanesup the world set 2022-08-02 09:58:06 -07:00
Dylan Baker 09c224dd7d main: cleanup after checking module versions 2022-07-27 14:21:15 -07:00
Dylan Baker ee06ab42d2 main: cleanup when validating
This clears up a few memory leaks in tests
2022-07-27 14:14:46 -07:00
Dylan Baker 7025581da8 cache: use pkgconf_dependency_free instead of just setting match = NULL
This also means that we don't need to call unref on the pkgs, they've
already been freed by the dependency_free code
2022-07-27 13:59:24 -07:00
Dylan Baker 21a645df00 queue: when flattening sets, unref dependencies that will not be re-added 2022-07-27 13:40:27 -07:00
Dylan Baker 798f2dac74 dependency: assert that there is never a negative number of references 2022-07-27 13:21:13 -07:00
Dylan Baker f809e0978e cache: when removing a pkg from the cache, unset the cached flag 2022-07-27 12:17:59 -07:00
Dylan Baker 2f5a2c56d4 dependency: add a reference to dependency when adding to graph
This makes internal uses more annoying, but fixes a potential bug in
libpkgconf where there are two pointers (one returned and on in the
graph), but only one refcount.
2022-07-27 11:59:12 -07:00
Dylan Baker 7cd86508a3 dependency: add refcount trace to dependency
This works like the pkg tracing, but for dependencies
2022-07-27 11:27:18 -07:00
Dylan Baker 283050cc42 pkg: assert a package being freed has 0 references 2022-07-26 15:19:15 -07:00
Dylan Baker 0f4f170ce2 pkg: make debug trace provide the name of the (un)refed package 2022-07-26 15:19:15 -07:00
Dylan Baker 94b6d96794 queue: unref pkg copy in flatten_dependency_set 2022-07-26 15:19:15 -07:00
Dylan Baker e9e7ebdbb6 cache: free allocated copy of cache_table in pkgconf_cache_free 2022-07-26 15:19:15 -07:00
7 changed files with 140 additions and 71 deletions

View File

@ -60,6 +60,30 @@ jobs:
run: |
meson test -v -C _build
debian-meson-asan:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Update system and add dependencies
run: |
apt-get update
apt-get install -y kyua atf-sh build-essential meson
- name: Build
run: |
meson _build -Db_sanitize=address
meson compile -C _build
- name: Run tests
run: |
meson test -v -C _build
env:
ASAN_OPTIONS: "exitcode=7"
debian-autotools:
runs-on: ubuntu-latest
container:

View File

@ -12,6 +12,21 @@ pipeline:
IMAGE: debian
BUILD: meson
debian-meson-asan:
image: debian:testing
environment:
- ASAN_OPTIONS="exitcode=7"
commands:
- apt-get update
- apt-get install -y kyua atf-sh build-essential meson
- meson _build -Db_sanitize=address
- meson compile -C _build
- meson test -v -C _build
when:
matrix:
IMAGE: debian
BUILD: meson
debian-autotools:
image: debian:testing
commands:

View File

@ -1162,7 +1162,7 @@ main(int argc, char *argv[])
if (required_module_version != NULL)
{
pkgconf_pkg_t *pkg;
pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1183,22 +1183,26 @@ main(int argc, char *argv[])
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
ret = EXIT_FAILURE;
goto out;
goto cleanup;
}
if (pkgconf_compare_version(pkg->version, required_module_version) >= 0)
{
ret = EXIT_SUCCESS;
goto out;
goto cleanup;
}
}
ret = EXIT_FAILURE;
cleanup:
if (pkg)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
}
else if (required_exact_module_version != NULL)
{
pkgconf_pkg_t *pkg;
pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1219,22 +1223,26 @@ main(int argc, char *argv[])
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
ret = EXIT_FAILURE;
goto out;
goto cleanup2;
}
if (pkgconf_compare_version(pkg->version, required_exact_module_version) == 0)
{
ret = EXIT_SUCCESS;
goto out;
goto cleanup2;
}
}
ret = EXIT_FAILURE;
cleanup2:
if (pkg)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
}
else if (required_max_module_version != NULL)
{
pkgconf_pkg_t *pkg;
pkgconf_pkg_t *pkg = NULL;
pkgconf_node_t *node;
pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
@ -1255,17 +1263,21 @@ main(int argc, char *argv[])
pkgconf_error(&pkg_client, "Package '%s' was not found\n", pkgiter->package);
ret = EXIT_FAILURE;
goto out;
goto cleanup3;
}
if (pkgconf_compare_version(pkg->version, required_max_module_version) <= 0)
{
ret = EXIT_SUCCESS;
goto out;
goto cleanup3;
}
}
ret = EXIT_FAILURE;
cleanup3:
if (pkg)
pkgconf_pkg_unref(&pkg_client, pkg);
pkgconf_dependency_free(&deplist);
goto out;
}
@ -1337,7 +1349,7 @@ main(int argc, char *argv[])
}
if ((want_flags & PKG_VALIDATE) == PKG_VALIDATE)
return 0;
goto out;
if ((want_flags & PKG_UNINSTALLED) == PKG_UNINSTALLED)
{

View File

@ -86,6 +86,9 @@ cache_dump(const pkgconf_client_t *client)
pkgconf_pkg_t *
pkgconf_cache_lookup(pkgconf_client_t *client, const char *id)
{
if (client->cache_table == NULL)
return NULL;
pkgconf_pkg_t **pkg;
pkg = bsearch(id, client->cache_table,
@ -153,6 +156,9 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
if (pkg == NULL)
return;
if (client->cache_table == NULL)
return;
if (!(pkg->flags & PKGCONF_PKG_PROPF_CACHED))
return;
@ -167,6 +173,8 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
if (slot == NULL)
return;
pkg->flags &= ~PKGCONF_PKG_PROPF_CACHED;
pkgconf_pkg_unref(client, pkg);
*slot = NULL;
qsort(client->cache_table, client->cache_count,
@ -181,19 +189,14 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
}
client->cache_count--;
if (client->cache_count == 0) {
free(client->cache_table);
client->cache_table = NULL;
}
else
{
client->cache_table = pkgconf_reallocarray(client->cache_table,
client->cache_count, sizeof(void *));
}
static inline void
clear_dependency_matches(pkgconf_list_t *list)
{
pkgconf_node_t *iter;
PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
{
pkgconf_dependency_t *dep = iter->data;
dep->match = NULL;
}
}
@ -211,30 +214,12 @@ clear_dependency_matches(pkgconf_list_t *list)
void
pkgconf_cache_free(pkgconf_client_t *client)
{
pkgconf_pkg_t **cache_table;
size_t i, count;
if (client->cache_table == NULL)
PKGCONF_TRACE(client, "cache is empty, not clearing");
return;
cache_table = pkgconf_reallocarray(NULL, client->cache_count, sizeof (void *));
memcpy(cache_table, client->cache_table,
client->cache_count * sizeof (void *));
/* first we clear cached match pointers */
for (i = 0, count = client->cache_count; i < count; i++)
{
pkgconf_pkg_t *pkg = cache_table[i];
clear_dependency_matches(&pkg->required);
clear_dependency_matches(&pkg->requires_private);
clear_dependency_matches(&pkg->provides);
clear_dependency_matches(&pkg->conflicts);
}
/* now forcibly free everything */
for (i = 0, count = client->cache_count; i < count; i++)
{
pkgconf_pkg_t *pkg = cache_table[i];
pkgconf_pkg_free(client, pkg);
}
while (client->cache_count > 0)
pkgconf_cache_remove(client, client->cache_table[0]);
PKGCONF_TRACE(client, "cleared package cache");
}

View File

@ -16,6 +16,8 @@
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include <assert.h>
/*
* !doc
*
@ -113,7 +115,7 @@ add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *d
}
PKGCONF_TRACE(client, "added dependency [%s] to list @%p; flags=%x", dependency_to_str(dep, depbuf, sizeof depbuf), list, dep->flags);
pkgconf_node_insert_tail(&dep->iter, dep, list);
pkgconf_node_insert_tail(&dep->iter, pkgconf_dependency_ref(dep->owner, dep), list);
return pkgconf_dependency_ref(dep->owner, dep);
}
@ -195,6 +197,9 @@ pkgconf_dependency_free_one(pkgconf_dependency_t *dep)
if (dep->match != NULL)
pkgconf_pkg_unref(dep->match->owner, dep->match);
if (dep->parent != NULL)
pkgconf_pkg_unref(dep->match->owner, dep->parent);
if (dep->package != NULL)
free(dep->package);
@ -222,6 +227,7 @@ pkgconf_dependency_ref(pkgconf_client_t *client, pkgconf_dependency_t *dep)
return NULL;
dep->refcount++;
PKGCONF_TRACE(client, "%s: refcount@%p: %d", dep->package, dep, dep->refcount);
return dep;
}
@ -242,7 +248,10 @@ pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep)
if (client != dep->owner)
return;
if (--dep->refcount <= 0)
dep->refcount--;
assert(dep->refcount >= 0);
PKGCONF_TRACE(client, "%s: refcount@%p: %d", dep->package, dep, dep->refcount);
if (dep->refcount == 0)
pkgconf_dependency_free_one(dep);
}
@ -354,7 +363,8 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
if (state == OUTSIDE_MODULE)
{
pkgconf_dependency_addraw(client, deplist_head, package, package_sz, NULL, 0, compare, flags);
pkgconf_dependency_t *dep = pkgconf_dependency_addraw(client, deplist_head, package, package_sz, NULL, 0, compare, flags);
pkgconf_dependency_unref(dep->owner, dep);
compare = PKGCONF_CMP_ANY;
package_sz = 0;
@ -398,7 +408,8 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h
version_sz = ptr - vstart;
state = OUTSIDE_MODULE;
pkgconf_dependency_addraw(client, deplist_head, package, package_sz, version, version_sz, compare, flags);
pkgconf_dependency_t *dep = pkgconf_dependency_addraw(client, deplist_head, package, package_sz, version, version_sz, compare, flags);
pkgconf_dependency_unref(dep->owner, dep);
compare = PKGCONF_CMP_ANY;
cnameptr = cmpname;

View File

@ -17,6 +17,8 @@
#include <libpkgconf/stdinc.h>
#include <libpkgconf/libpkgconf.h>
#include <assert.h>
/*
* !doc
*
@ -451,7 +453,8 @@ pkgconf_pkg_new_from_file(pkgconf_client_t *client, const char *filename, FILE *
return NULL;
}
pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0);
pkgconf_dependency_t *dep = pkgconf_dependency_add(client, &pkg->provides, pkg->id, pkg->version, PKGCONF_CMP_EQUAL, 0);
pkgconf_dependency_unref(dep->owner, dep);
return pkgconf_pkg_ref(client, pkg);
}
@ -514,6 +517,8 @@ pkgconf_pkg_free(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
if (pkg->pc_filedir != NULL)
free(pkg->pc_filedir);
/* We shouldn't be trying to free this if someone is still holding a reference to it */
assert(pkg->refcount == 0);
free(pkg);
}
@ -536,7 +541,7 @@ pkgconf_pkg_ref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_TRACE(client, "WTF: client %p refers to package %p owned by other client %p", client, pkg, pkg->owner);
pkg->refcount++;
PKGCONF_TRACE(client, "refcount@%p: %d", pkg, pkg->refcount);
PKGCONF_TRACE(client, "%s: refcount@%p: %d", pkg->id, pkg, pkg->refcount);
return pkg;
}
@ -559,7 +564,7 @@ pkgconf_pkg_unref(pkgconf_client_t *client, pkgconf_pkg_t *pkg)
PKGCONF_TRACE(client, "WTF: client %p unrefs package %p owned by other client %p", client, pkg, pkg->owner);
pkg->refcount--;
PKGCONF_TRACE(pkg->owner, "refcount@%p: %d", pkg, pkg->refcount);
PKGCONF_TRACE(pkg->owner, "%s: refcount@%p: %d", pkg->id, pkg, pkg->refcount);
if (pkg->refcount <= 0)
pkgconf_pkg_free(pkg->owner, pkg);

View File

@ -116,6 +116,18 @@ pkgconf_queue_collect_dependents(pkgconf_client_t *client, pkgconf_pkg_t *pkg, v
if (pkg == world)
return;
if ((pkg->flags & PKGCONF_PKG_PROPF_STATIC) == PKGCONF_PKG_PROPF_STATIC) {
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, node->data);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->requires_private);
}
}
else
{
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
{
pkgconf_dependency_t *flattened_dep;
@ -124,14 +136,6 @@ pkgconf_queue_collect_dependents(pkgconf_client_t *client, pkgconf_pkg_t *pkg, v
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->required);
}
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
{
pkgconf_dependency_t *flattened_dep;
flattened_dep = pkgconf_dependency_copy(client, node->data);
pkgconf_node_insert(&flattened_dep->iter, flattened_dep, &world->requires_private);
}
}
@ -147,11 +151,11 @@ dep_sort_cmp(const void *a, const void *b)
static inline void
flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
{
pkgconf_node_t *node;
pkgconf_node_t *node, *next;
pkgconf_dependency_t **deps = NULL;
size_t dep_count = 0, i;
PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
{
pkgconf_dependency_t *dep = node->data;
pkgconf_pkg_t *pkg = pkgconf_pkg_verify_dependency(client, dep, NULL);
@ -160,7 +164,11 @@ flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
continue;
if (pkg->serial == client->serial)
continue;
{
PKGCONF_TRACE(client, "dedup %s serials match", pkg->id);
pkgconf_dependency_unref(dep->owner, dep);
goto next;
}
if (dep->match == NULL)
{
@ -178,6 +186,7 @@ flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
if (!strcmp(dep->package, other_dep->package))
{
PKGCONF_TRACE(client, "skipping, %zu deps", dep_count);
pkgconf_dependency_unref(dep->owner, dep);
goto next;
}
}
@ -191,9 +200,13 @@ flatten_dependency_set(pkgconf_client_t *client, pkgconf_list_t *list)
PKGCONF_TRACE(client, "added %s to dep table", dep->package);
next:;
next:
pkgconf_pkg_unref(client, pkg);
}
if (deps == NULL)
return;
qsort(deps, dep_count, sizeof (void *), dep_sort_cmp);
/* zero the list and start readding */
@ -266,24 +279,28 @@ pkgconf_queue_apply(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_queu
.realname = "virtual world package",
.flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
};
bool ret = false;
/* if maxdepth is one, then we will not traverse deeper than our virtual package. */
if (!maxdepth)
maxdepth = -1;
if (pkgconf_queue_verify(client, &world, list, maxdepth) != PKGCONF_PKG_ERRF_OK)
return false;
{
goto out;
}
/* the world dependency set is flattened after it is returned from pkgconf_queue_verify */
if (!func(client, &world, data, maxdepth))
{
pkgconf_pkg_free(client, &world);
return false;
goto out;
}
pkgconf_pkg_free(client, &world);
return true;
ret = true;
out:
pkgconf_pkg_free(client, &world);
return ret;
}
/*