aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Staletic <boris.staletic@protonmail.com>2024-03-28 19:08:00 +0100
committerFabian Groffen <grobian@gentoo.org>2024-03-29 11:57:17 +0100
commit268c2076b5276fbce37df3f751619646c4b8d7a4 (patch)
tree027885f85a13b0f1d75347f95ff330ab4b5d8c8e
parentqmerge: add reminder for myself (diff)
downloadportage-utils-268c2076b5276fbce37df3f751619646c4b8d7a4.tar.gz
portage-utils-268c2076b5276fbce37df3f751619646c4b8d7a4.tar.bz2
portage-utils-268c2076b5276fbce37df3f751619646c4b8d7a4.zip
qlop: Properly handle atom_compar_cb when called from qsort
`qsort` passes pointers to elements ("iterators" in C++ lingo) to the callback, not elements directly. Hence `l` and `r` in `atom_compar_cb` actually receives `depend_atom**`, but only when called from `qsort`. The other two call sites (`tree_pkg_compar` and `pkg_sort_cb`) actually apssed `depend_atom*`. This leads to type casting confusion and undefined behaviour for any invocation of `qlop -p`. First discovered by SEGFAULT-ing with the following invocation: qlop -p `cat /var/lib/portage/world` Valgrind and ASAN made triggering the SEGFAULT easier - any invocation with two or more atoms triggered a NULL dereference. This commit addresses the above problem: 1. Expect that `atom_compar_cb` is actually called with two `depend_atom**`. 2. Make `tree_pkg_compar` and `pkg_sort_cb` comply with the above change, by passing `&al` and `&ar`, instead of `al` and `ar`. Signed-off-by: Fabian Groffen <grobian@gentoo.org>
-rw-r--r--libq/atom.c4
-rw-r--r--libq/tree.c2
-rw-r--r--qlop.c2
3 files changed, 4 insertions, 4 deletions
diff --git a/libq/atom.c b/libq/atom.c
index b1a150a..3cc2100 100644
--- a/libq/atom.c
+++ b/libq/atom.c
@@ -1242,8 +1242,8 @@ atom_format(const char *format, const depend_atom *atom)
inline int
atom_compar_cb(const void *l, const void *r)
{
- const depend_atom *al = l;
- const depend_atom *ar = r;
+ const depend_atom *al = *(const depend_atom**)l;
+ const depend_atom *ar = *(const depend_atom**)r;
switch (atom_compare(al, ar)) {
case EQUAL: return 0;
diff --git a/libq/tree.c b/libq/tree.c
index 4678634..335ac79 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -463,7 +463,7 @@ tree_pkg_compar(const void *l, const void *r)
depend_atom *al = tree_get_atom(pl, false);
depend_atom *ar = tree_get_atom(pr, false);
- return atom_compar_cb(al, ar);
+ return atom_compar_cb(&al, &ar);
}
static tree_pkg_ctx *
diff --git a/qlop.c b/qlop.c
index 3e6db53..cfad246 100644
--- a/qlop.c
+++ b/qlop.c
@@ -309,7 +309,7 @@ pkg_sort_cb(const void *l, const void *r)
depend_atom *al = pl->atom;
depend_atom *ar = pr->atom;
- return atom_compar_cb(al, ar);
+ return atom_compar_cb(&al, &ar);
}
/* The format of the sync log has changed over time.