f8539f
From e1973fb24917234e552a711de16e2fc19f477b63 Mon Sep 17 00:00:00 2001
f8539f
From: Michal Privoznik <mprivozn@redhat.com>
f8539f
Date: Wed, 22 Nov 2023 14:58:49 +0100
f8539f
Subject: [PATCH 8/8] lib: Replace qsort() with g_qsort_with_data()
f8539f
f8539f
While glibc provides qsort(), which usually is just a mergesort,
f8539f
until sorting arrays so huge that temporary array used by
f8539f
mergesort would not fit into physical memory (which in our case
f8539f
is never), we are not guaranteed it'll use mergesort. The
f8539f
advantage of mergesort is clear - it's stable. IOW, if we have an
f8539f
array of values parsed from XML, qsort() it and produce some
f8539f
output based on those values, we can then compare the output with
f8539f
some expected output, line by line.
f8539f
f8539f
But with newer glibc this is all history. After [1], qsort() is
f8539f
no longer mergesort but introsort instead, which is not stable.
f8539f
This is suboptimal, because in some cases we want to preserve
f8539f
order of equal items. For instance, in ebiptablesApplyNewRules(),
f8539f
nwfilter rules are sorted by their priority. But if two rules
f8539f
have the same priority, we want to keep them in the order they
f8539f
appear in the XML. Since it's hard/needless work to identify
f8539f
places where stable or unstable sorting is needed, let's just
f8539f
play it safe and use stable sorting everywhere.
f8539f
f8539f
Fortunately, glib provides g_qsort_with_data() which indeed
f8539f
implement mergesort and it's a drop in replacement for qsort(),
f8539f
almost. It accepts fifth argument (pointer to opaque data), that
f8539f
is passed to comparator function, which then accepts three
f8539f
arguments.
f8539f
f8539f
We have to keep one occurance of qsort() though - in NSS module
f8539f
which deliberately does not link with glib.
f8539f
f8539f
1: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=03bf8357e8291857a435afcc3048e0b697b6cc04
f8539f
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
f8539f
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
f8539f
(cherry picked from commit cfcbba4c2b8a2062dec36072a34209229b6c3277)
f8539f
---
f8539f
 build-aux/Makefile.nonreentrant           |  1 -
f8539f
 build-aux/syntax-check.mk                 |  2 +-
f8539f
 src/conf/capabilities.c                   |  8 ++++---
f8539f
 src/conf/domain_conf.c                    |  6 +++--
f8539f
 src/cpu/cpu.c                             |  7 +++---
f8539f
 src/cpu/cpu_x86.c                         | 15 +++++++-----
f8539f
 src/lxc/lxc_container.c                   |  3 ++-
f8539f
 src/nwfilter/nwfilter_ebiptables_driver.c | 29 +++++++++++++++--------
f8539f
 src/qemu/qemu_monitor_json.c              |  6 +++--
f8539f
 src/qemu/qemu_process.c                   |  7 +++---
f8539f
 src/security/security_manager.c           |  9 ++++---
f8539f
 src/util/virfile.c                        |  8 ++++---
f8539f
 src/util/virhash.c                        |  9 ++++---
f8539f
 src/util/virresctrl.c                     |  9 ++++---
f8539f
 src/util/virstring.c                      | 12 ++++++----
f8539f
 src/util/virstring.h                      |  8 +++++--
f8539f
 src/util/virtypedparam.c                  |  9 ++++---
f8539f
 tests/commandhelper.c                     |  6 +++--
f8539f
 tests/virstringtest.c                     |  8 +++----
f8539f
 tools/virsh-checkpoint.c                  | 10 ++++----
f8539f
 tools/virsh-domain-monitor.c              | 11 +++++----
f8539f
 tools/virsh-host.c                        |  7 ++++--
f8539f
 tools/virsh-interface.c                   | 11 +++++----
f8539f
 tools/virsh-network.c                     | 29 +++++++++++++++--------
f8539f
 tools/virsh-nodedev.c                     | 11 +++++----
f8539f
 tools/virsh-nwfilter.c                    | 22 ++++++++++-------
f8539f
 tools/virsh-pool.c                        | 11 +++++----
f8539f
 tools/virsh-secret.c                      | 11 +++++----
f8539f
 tools/virsh-snapshot.c                    | 10 ++++----
f8539f
 tools/virsh-volume.c                      | 10 +++++---
f8539f
 30 files changed, 195 insertions(+), 110 deletions(-)
f8539f
f8539f
diff --git a/build-aux/Makefile.nonreentrant b/build-aux/Makefile.nonreentrant
f8539f
index 87bb9db20e..b869c645ce 100644
f8539f
--- a/build-aux/Makefile.nonreentrant
f8539f
+++ b/build-aux/Makefile.nonreentrant
f8539f
@@ -21,7 +21,6 @@
f8539f
 #      | grep '_r$' \
f8539f
 #      | awk '{print $3}' \
f8539f
 #      | grep -v __ \
f8539f
-#      | grep -v qsort \ # Red herring since we don't need to pass extra args to qsort comparator
f8539f
 #      | grep -v readdir \ # This is safe as long as each DIR * instance is only used by one thread
f8539f
 #      | sort \
f8539f
 #      | uniq \
f8539f
diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
f8539f
index 7af7d20d70..ad2ecd50c7 100644
f8539f
--- a/build-aux/syntax-check.mk
f8539f
+++ b/build-aux/syntax-check.mk
f8539f
@@ -380,7 +380,7 @@ sc_prohibit_unsigned_pid:
f8539f
 # Many of the function names below came from this filter:
f8539f
 # git grep -B2 '\<_('|grep -E '\.c- *[[:alpha:]_][[:alnum:]_]* ?\(.*[,;]$' \
f8539f
 # |sed 's/.*\.c-  *//'|perl -pe 's/ ?\(.*//'|sort -u \
f8539f
-# |grep -vE '^(qsort|if|close|assert|fputc|free|N_|vir.*GetName|.*Unlock|virNodeListDevices|virHashRemoveEntry|freeaddrinfo|.*[fF]ree|xdrmem_create|xmlXPathFreeObject|virUUIDFormat|openvzSetProgramSentinal|polkit_action_unref)$'
f8539f
+# |grep -vE '^(if|close|assert|fputc|free|N_|vir.*GetName|.*Unlock|virNodeListDevices|virHashRemoveEntry|freeaddrinfo|.*[fF]ree|xdrmem_create|xmlXPathFreeObject|virUUIDFormat|openvzSetProgramSentinal|polkit_action_unref)$'
f8539f
 
f8539f
 msg_gen_function =
f8539f
 msg_gen_function += VIR_ERROR
f8539f
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
f8539f
index 34f04cb7d3..32badee7b3 100644
f8539f
--- a/src/conf/capabilities.c
f8539f
+++ b/src/conf/capabilities.c
f8539f
@@ -2073,7 +2073,8 @@ virCapsHostCacheBankFree(virCapsHostCacheBank *ptr)
f8539f
 
f8539f
 static int
f8539f
 virCapsHostCacheBankSorter(const void *a,
f8539f
-                           const void *b)
f8539f
+                           const void *b,
f8539f
+                           void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virCapsHostCacheBank *ca = *(virCapsHostCacheBank **)a;
f8539f
     virCapsHostCacheBank *cb = *(virCapsHostCacheBank **)b;
f8539f
@@ -2273,8 +2274,9 @@ virCapabilitiesInitCaches(virCaps *caps)
f8539f
      * still traverse the directory instead of guessing names (in case there is
f8539f
      * 'index1' and 'index3' but no 'index2'). */
f8539f
     if (caps->host.cache.banks) {
f8539f
-        qsort(caps->host.cache.banks, caps->host.cache.nbanks,
f8539f
-              sizeof(*caps->host.cache.banks), virCapsHostCacheBankSorter);
f8539f
+        g_qsort_with_data(caps->host.cache.banks, caps->host.cache.nbanks,
f8539f
+                          sizeof(*caps->host.cache.banks),
f8539f
+                          virCapsHostCacheBankSorter, NULL);
f8539f
     }
f8539f
 
f8539f
     if (virCapabilitiesInitResctrlMemory(caps) < 0)
f8539f
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
f8539f
index 2b6f765b6d..aede47a130 100644
f8539f
--- a/src/conf/domain_conf.c
f8539f
+++ b/src/conf/domain_conf.c
f8539f
@@ -15703,7 +15703,9 @@ virDomainDefParseBootXML(xmlXPathContextPtr ctxt,
f8539f
 }
f8539f
 
f8539f
 
f8539f
-static int virDomainIdMapEntrySort(const void *a, const void *b)
f8539f
+static int virDomainIdMapEntrySort(const void *a,
f8539f
+                                   const void *b,
f8539f
+                                   void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const virDomainIdMapEntry *entrya = a;
f8539f
     const virDomainIdMapEntry *entryb = b;
f8539f
@@ -15746,7 +15748,7 @@ virDomainIdmapDefParseXML(xmlXPathContextPtr ctxt,
f8539f
         }
f8539f
     }
f8539f
 
f8539f
-    qsort(idmap, num, sizeof(idmap[0]), virDomainIdMapEntrySort);
f8539f
+    g_qsort_with_data(idmap, num, sizeof(idmap[0]), virDomainIdMapEntrySort, NULL);
f8539f
 
f8539f
     return idmap;
f8539f
 }
f8539f
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
f8539f
index bb5737e938..bc43aa4e93 100644
f8539f
--- a/src/cpu/cpu.c
f8539f
+++ b/src/cpu/cpu.c
f8539f
@@ -1045,7 +1045,8 @@ virCPUConvertLegacy(virArch arch,
f8539f
 
f8539f
 static int
f8539f
 virCPUFeatureCompare(const void *p1,
f8539f
-                     const void *p2)
f8539f
+                     const void *p2,
f8539f
+                     void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const virCPUFeatureDef *f1 = p1;
f8539f
     const virCPUFeatureDef *f2 = p2;
f8539f
@@ -1085,8 +1086,8 @@ virCPUExpandFeatures(virArch arch,
f8539f
         driver->expandFeatures(cpu) < 0)
f8539f
         return -1;
f8539f
 
f8539f
-    qsort(cpu->features, cpu->nfeatures, sizeof(*cpu->features),
f8539f
-          virCPUFeatureCompare);
f8539f
+    g_qsort_with_data(cpu->features, cpu->nfeatures, sizeof(*cpu->features),
f8539f
+                      virCPUFeatureCompare, NULL);
f8539f
 
f8539f
     VIR_DEBUG("nfeatures=%zu", cpu->nfeatures);
f8539f
     return 0;
f8539f
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
f8539f
index 7a7f3b409d..8d0e3947ce 100644
f8539f
--- a/src/cpu/cpu_x86.c
f8539f
+++ b/src/cpu/cpu_x86.c
f8539f
@@ -393,7 +393,9 @@ x86FeatureFindInternal(const char *name)
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-virCPUx86DataSorter(const void *a, const void *b)
f8539f
+virCPUx86DataSorter(const void *a,
f8539f
+                    const void *b,
f8539f
+                    void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virCPUx86DataItem *da = (virCPUx86DataItem *) a;
f8539f
     virCPUx86DataItem *db = (virCPUx86DataItem *) b;
f8539f
@@ -437,7 +439,7 @@ static int
f8539f
 virCPUx86DataItemCmp(const virCPUx86DataItem *item1,
f8539f
                      const virCPUx86DataItem *item2)
f8539f
 {
f8539f
-    return virCPUx86DataSorter(item1, item2);
f8539f
+    return virCPUx86DataSorter(item1, item2, NULL);
f8539f
 }
f8539f
 
f8539f
 
f8539f
@@ -541,8 +543,9 @@ virCPUx86DataAddItem(virCPUx86Data *data,
f8539f
         VIR_APPEND_ELEMENT_COPY(data->items, data->len,
f8539f
                                 *((virCPUx86DataItem *)item));
f8539f
 
f8539f
-        qsort(data->items, data->len,
f8539f
-              sizeof(virCPUx86DataItem), virCPUx86DataSorter);
f8539f
+        g_qsort_with_data(data->items, data->len,
f8539f
+                          sizeof(virCPUx86DataItem),
f8539f
+                          virCPUx86DataSorter, NULL);
f8539f
     }
f8539f
 
f8539f
     return 0;
f8539f
@@ -3465,8 +3468,8 @@ virCPUx86DataGetHost(void)
f8539f
     }
f8539f
 
f8539f
     /* the rest of the code expects the function to be in order */
f8539f
-    qsort(cpuid->data.x86.items, cpuid->data.x86.len,
f8539f
-          sizeof(virCPUx86DataItem), virCPUx86DataSorter);
f8539f
+    g_qsort_with_data(cpuid->data.x86.items, cpuid->data.x86.len,
f8539f
+                      sizeof(virCPUx86DataItem), virCPUx86DataSorter, NULL);
f8539f
 
f8539f
     return cpuid;
f8539f
 }
f8539f
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
f8539f
index 35a882171b..652697890f 100644
f8539f
--- a/src/lxc/lxc_container.c
f8539f
+++ b/src/lxc/lxc_container.c
f8539f
@@ -791,7 +791,8 @@ static int lxcContainerSetReadOnly(void)
f8539f
     if (!mounts)
f8539f
         return 0;
f8539f
 
f8539f
-    qsort(mounts, nmounts, sizeof(mounts[0]), virStringSortRevCompare);
f8539f
+    g_qsort_with_data(mounts, nmounts,
f8539f
+                      sizeof(mounts[0]), virStringSortRevCompare, NULL);
f8539f
 
f8539f
     /* turn 'mounts' into a proper GStrv */
f8539f
     VIR_EXPAND_N(mounts, nmounts, 1);
f8539f
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
f8539f
index 1c5da2ae05..56bddb9097 100644
f8539f
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
f8539f
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
f8539f
@@ -3087,7 +3087,9 @@ virNWFilterRuleInstSort(const void *a, const void *b)
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-virNWFilterRuleInstSortPtr(const void *a, const void *b)
f8539f
+virNWFilterRuleInstSortPtr(const void *a,
f8539f
+                           const void *b,
f8539f
+                           void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNWFilterRuleInst * const *insta = a;
f8539f
     virNWFilterRuleInst * const *instb = b;
f8539f
@@ -3097,7 +3099,8 @@ virNWFilterRuleInstSortPtr(const void *a, const void *b)
f8539f
 
f8539f
 static int
f8539f
 ebiptablesFilterOrderSort(const void *va,
f8539f
-                          const void *vb)
f8539f
+                          const void *vb,
f8539f
+                          void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const virHashKeyValuePair *a = va;
f8539f
     const virHashKeyValuePair *b = vb;
f8539f
@@ -3244,7 +3247,9 @@ struct _ebtablesSubChainInst {
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-ebtablesSubChainInstSort(const void *a, const void *b)
f8539f
+ebtablesSubChainInstSort(const void *a,
f8539f
+                         const void *b,
f8539f
+                         void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const ebtablesSubChainInst **insta = (const ebtablesSubChainInst **)a;
f8539f
     const ebtablesSubChainInst **instb = (const ebtablesSubChainInst **)b;
f8539f
@@ -3268,7 +3273,8 @@ ebtablesGetSubChainInsts(GHashTable *chains,
f8539f
     if (filter_names == NULL)
f8539f
         return -1;
f8539f
 
f8539f
-    qsort(filter_names, nfilter_names, sizeof(*filter_names), ebiptablesFilterOrderSort);
f8539f
+    g_qsort_with_data(filter_names, nfilter_names,
f8539f
+                      sizeof(*filter_names), ebiptablesFilterOrderSort, NULL);
f8539f
 
f8539f
     for (i = 0; filter_names[i].key; i++) {
f8539f
         g_autofree ebtablesSubChainInst *inst = NULL;
f8539f
@@ -3306,9 +3312,10 @@ ebiptablesApplyNewRules(const char *ifname,
f8539f
     size_t nsubchains = 0;
f8539f
     int ret = -1;
f8539f
 
f8539f
-    if (nrules)
f8539f
-        qsort(rules, nrules, sizeof(rules[0]),
f8539f
-              virNWFilterRuleInstSortPtr);
f8539f
+    if (nrules) {
f8539f
+        g_qsort_with_data(rules, nrules, sizeof(rules[0]),
f8539f
+                          virNWFilterRuleInstSortPtr, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* cleanup whatever may exist */
f8539f
     virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
f8539f
@@ -3388,9 +3395,11 @@ ebiptablesApplyNewRules(const char *ifname,
f8539f
                 goto cleanup;
f8539f
         }
f8539f
 
f8539f
-        if (nsubchains > 0)
f8539f
-            qsort(subchains, nsubchains, sizeof(subchains[0]),
f8539f
-                  ebtablesSubChainInstSort);
f8539f
+        if (nsubchains > 0) {
f8539f
+            g_qsort_with_data(subchains, nsubchains,
f8539f
+                              sizeof(subchains[0]),
f8539f
+                              ebtablesSubChainInstSort, NULL);
f8539f
+        }
f8539f
 
f8539f
         for (i = 0, j = 0; i < nrules; i++) {
f8539f
             if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
f8539f
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
f8539f
index 105d729d7c..6f1dffe8f7 100644
f8539f
--- a/src/qemu/qemu_monitor_json.c
f8539f
+++ b/src/qemu/qemu_monitor_json.c
f8539f
@@ -7607,7 +7607,8 @@ qemuMonitorJSONProcessHotpluggableCpusReply(virJSONValue *vcpu,
f8539f
 
f8539f
 static int
f8539f
 qemuMonitorQueryHotpluggableCpusEntrySort(const void *p1,
f8539f
-                                          const void *p2)
f8539f
+                                          const void *p2,
f8539f
+                                          void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const struct qemuMonitorQueryHotpluggableCpusEntry *a = p1;
f8539f
     const struct qemuMonitorQueryHotpluggableCpusEntry *b = p2;
f8539f
@@ -7659,7 +7660,8 @@ qemuMonitorJSONGetHotpluggableCPUs(qemuMonitor *mon,
f8539f
             goto cleanup;
f8539f
     }
f8539f
 
f8539f
-    qsort(info, ninfo, sizeof(*info), qemuMonitorQueryHotpluggableCpusEntrySort);
f8539f
+    g_qsort_with_data(info, ninfo, sizeof(*info),
f8539f
+                      qemuMonitorQueryHotpluggableCpusEntrySort, NULL);
f8539f
 
f8539f
     *entries = g_steal_pointer(&info;;
f8539f
     *nentries = ninfo;
f8539f
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
f8539f
index b9267d8699..f32e82bbd1 100644
f8539f
--- a/src/qemu/qemu_process.c
f8539f
+++ b/src/qemu/qemu_process.c
f8539f
@@ -6093,7 +6093,8 @@ qemuDomainHasHotpluggableStartupVcpus(virDomainDef *def)
f8539f
 
f8539f
 static int
f8539f
 qemuProcessVcpusSortOrder(const void *a,
f8539f
-                          const void *b)
f8539f
+                          const void *b,
f8539f
+                          void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virDomainVcpuDef *vcpua = *((virDomainVcpuDef **)a);
f8539f
     virDomainVcpuDef *vcpub = *((virDomainVcpuDef **)b);
f8539f
@@ -6133,8 +6134,8 @@ qemuProcessSetupHotpluggableVcpus(virDomainObj *vm,
f8539f
     if (nbootHotplug == 0)
f8539f
         return 0;
f8539f
 
f8539f
-    qsort(bootHotplug, nbootHotplug, sizeof(*bootHotplug),
f8539f
-          qemuProcessVcpusSortOrder);
f8539f
+    g_qsort_with_data(bootHotplug, nbootHotplug,
f8539f
+                      sizeof(*bootHotplug), qemuProcessVcpusSortOrder, NULL);
f8539f
 
f8539f
     if (virDomainCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0)
f8539f
         goto cleanup;
f8539f
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
f8539f
index 5df0cd3419..afd41f1c20 100644
f8539f
--- a/src/security/security_manager.c
f8539f
+++ b/src/security/security_manager.c
f8539f
@@ -1247,7 +1247,9 @@ virSecurityManagerRestoreNetdevLabel(virSecurityManager *mgr,
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-cmpstringp(const void *p1, const void *p2)
f8539f
+cmpstringp(const void *p1,
f8539f
+           const void *p2,
f8539f
+           void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const char *s1 = *(char * const *) p1;
f8539f
     const char *s2 = *(char * const *) p2;
f8539f
@@ -1303,8 +1305,9 @@ virSecurityManagerMetadataLock(virSecurityManager *mgr G_GNUC_UNUSED,
f8539f
      * paths in the same order and thus no deadlock can occur.
f8539f
      * Lastly, it makes searching for duplicate paths below
f8539f
      * simpler. */
f8539f
-    if (paths)
f8539f
-        qsort(paths, npaths, sizeof(*paths), cmpstringp);
f8539f
+    if (paths) {
f8539f
+        g_qsort_with_data(paths, npaths, sizeof(*paths), cmpstringp, NULL);
f8539f
+    }
f8539f
 
f8539f
     for (i = 0; i < npaths; i++) {
f8539f
         const char *p = paths[i];
f8539f
diff --git a/src/util/virfile.c b/src/util/virfile.c
f8539f
index 54708652fb..007b6cf512 100644
f8539f
--- a/src/util/virfile.c
f8539f
+++ b/src/util/virfile.c
f8539f
@@ -2193,9 +2193,11 @@ virFileGetMountSubtreeImpl(const char *mtabpath,
f8539f
         mounts[nmounts - 2] = g_strdup(mntent.mnt_dir);
f8539f
     }
f8539f
 
f8539f
-    if (mounts)
f8539f
-        qsort(mounts, nmounts - 1, sizeof(mounts[0]),
f8539f
-              reverse ? virStringSortRevCompare : virStringSortCompare);
f8539f
+    if (mounts) {
f8539f
+        g_qsort_with_data(mounts, nmounts - 1, sizeof(mounts[0]),
f8539f
+                          reverse ? virStringSortRevCompare : virStringSortCompare,
f8539f
+                          NULL);
f8539f
+    }
f8539f
 
f8539f
     *mountsret = mounts;
f8539f
     *nmountsret = nmounts ? nmounts - 1 : 0;
f8539f
diff --git a/src/util/virhash.c b/src/util/virhash.c
f8539f
index 8365f51eb3..19908c9412 100644
f8539f
--- a/src/util/virhash.c
f8539f
+++ b/src/util/virhash.c
f8539f
@@ -514,7 +514,8 @@ void *virHashSearch(GHashTable *table,
f8539f
 
f8539f
 static int
f8539f
 virHashGetItemsKeySorter(const void *va,
f8539f
-                         const void *vb)
f8539f
+                         const void *vb,
f8539f
+                         void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const virHashKeyValuePair *a = va;
f8539f
     const virHashKeyValuePair *b = vb;
f8539f
@@ -552,8 +553,10 @@ virHashGetItems(GHashTable *table,
f8539f
         i++;
f8539f
     }
f8539f
 
f8539f
-    if (sortKeys)
f8539f
-        qsort(items, *nitems, sizeof(*items), virHashGetItemsKeySorter);
f8539f
+    if (sortKeys) {
f8539f
+        g_qsort_with_data(items, *nitems,
f8539f
+                          sizeof(*items), virHashGetItemsKeySorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     return items;
f8539f
 }
f8539f
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
f8539f
index 8ca58f5d10..30ae25c487 100644
f8539f
--- a/src/util/virresctrl.c
f8539f
+++ b/src/util/virresctrl.c
f8539f
@@ -2522,7 +2522,8 @@ virResctrlMonitorRemove(virResctrlMonitor *monitor)
f8539f
 
f8539f
 static int
f8539f
 virResctrlMonitorStatsSorter(const void *a,
f8539f
-                             const void *b)
f8539f
+                             const void *b,
f8539f
+                             void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     return (*(virResctrlMonitorStats **)a)->id
f8539f
         - (*(virResctrlMonitorStats **)b)->id;
f8539f
@@ -2625,8 +2626,10 @@ virResctrlMonitorGetStats(virResctrlMonitor *monitor,
f8539f
     }
f8539f
 
f8539f
     /* Sort in id's ascending order */
f8539f
-    if (*nstats)
f8539f
-        qsort(*stats, *nstats, sizeof(**stats), virResctrlMonitorStatsSorter);
f8539f
+    if (*nstats) {
f8539f
+        g_qsort_with_data(*stats, *nstats, sizeof(**stats),
f8539f
+                          virResctrlMonitorStatsSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     ret = 0;
f8539f
  cleanup:
f8539f
diff --git a/src/util/virstring.c b/src/util/virstring.c
f8539f
index 6b728ff047..81c9aff304 100644
f8539f
--- a/src/util/virstring.c
f8539f
+++ b/src/util/virstring.c
f8539f
@@ -518,9 +518,11 @@ virStringIsEmpty(const char *str)
f8539f
  * virStringSortCompare:
f8539f
  *
f8539f
  * A comparator function for sorting strings in
f8539f
- * normal order with qsort().
f8539f
+ * normal order with g_qsort_with_data().
f8539f
  */
f8539f
-int virStringSortCompare(const void *a, const void *b)
f8539f
+int virStringSortCompare(const void *a,
f8539f
+                         const void *b,
f8539f
+                         void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const char **sa = (const char**)a;
f8539f
     const char **sb = (const char**)b;
f8539f
@@ -532,9 +534,11 @@ int virStringSortCompare(const void *a, const void *b)
f8539f
  * virStringSortRevCompare:
f8539f
  *
f8539f
  * A comparator function for sorting strings in
f8539f
- * reverse order with qsort().
f8539f
+ * reverse order with g_qsort_with_data().
f8539f
  */
f8539f
-int virStringSortRevCompare(const void *a, const void *b)
f8539f
+int virStringSortRevCompare(const void *a,
f8539f
+                            const void *b,
f8539f
+                            void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const char **sa = (const char**)a;
f8539f
     const char **sb = (const char**)b;
f8539f
diff --git a/src/util/virstring.h b/src/util/virstring.h
f8539f
index 16dcce98f4..8f9b1edc8f 100644
f8539f
--- a/src/util/virstring.h
f8539f
+++ b/src/util/virstring.h
f8539f
@@ -83,8 +83,12 @@ bool virStringIsEmpty(const char *str);
f8539f
 int virStrcpy(char *dest, const char *src, size_t destbytes);
f8539f
 #define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest))
f8539f
 
f8539f
-int virStringSortCompare(const void *a, const void *b);
f8539f
-int virStringSortRevCompare(const void *a, const void *b);
f8539f
+int virStringSortCompare(const void *a,
f8539f
+                         const void *b,
f8539f
+                         void *opaque);
f8539f
+int virStringSortRevCompare(const void *a,
f8539f
+                            const void *b,
f8539f
+                            void *opaque);
f8539f
 int virStringToUpper(char **dst, const char *src);
f8539f
 
f8539f
 ssize_t virStringSearch(const char *str,
f8539f
diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c
f8539f
index ef3b8052f6..1be249d855 100644
f8539f
--- a/src/util/virtypedparam.c
f8539f
+++ b/src/util/virtypedparam.c
f8539f
@@ -43,7 +43,9 @@ VIR_ENUM_IMPL(virTypedParameter,
f8539f
 );
f8539f
 
f8539f
 static int
f8539f
-virTypedParamsSortName(const void *left, const void *right)
f8539f
+virTypedParamsSortName(const void *left,
f8539f
+                       const void *right,
f8539f
+                       void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const virTypedParameter *param_left = left, *param_right = right;
f8539f
     return strcmp(param_left->field, param_right->field);
f8539f
@@ -78,7 +80,8 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...)
f8539f
 
f8539f
     /* Here we intentionally don't copy values */
f8539f
     memcpy(sorted, params, sizeof(*params) * nparams);
f8539f
-    qsort(sorted, nparams, sizeof(*sorted), virTypedParamsSortName);
f8539f
+    g_qsort_with_data(sorted, nparams,
f8539f
+                      sizeof(*sorted), virTypedParamsSortName, NULL);
f8539f
 
f8539f
     name = va_arg(ap, const char *);
f8539f
     while (name) {
f8539f
@@ -102,7 +105,7 @@ virTypedParamsValidate(virTypedParameterPtr params, int nparams, ...)
f8539f
 
f8539f
     va_end(ap);
f8539f
 
f8539f
-    qsort(keys, nkeys, sizeof(*keys), virTypedParamsSortName);
f8539f
+    g_qsort_with_data(keys, nkeys, sizeof(*keys), virTypedParamsSortName, NULL);
f8539f
 
f8539f
     for (i = 0, j = 0; i < nparams && j < nkeys;) {
f8539f
         if (STRNEQ(sorted[i].field, keys[j].field)) {
f8539f
diff --git a/tests/commandhelper.c b/tests/commandhelper.c
f8539f
index 9b56feb120..9f28aa7674 100644
f8539f
--- a/tests/commandhelper.c
f8539f
+++ b/tests/commandhelper.c
f8539f
@@ -129,7 +129,9 @@ static void printArguments(FILE *log, int argc, char** argv)
f8539f
     }
f8539f
 }
f8539f
 
f8539f
-static int envsort(const void *a, const void *b)
f8539f
+static int envsort(const void *a,
f8539f
+                   const void *b,
f8539f
+                   void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const char *astr = *(const char**)a;
f8539f
     const char *bstr = *(const char**)b;
f8539f
@@ -165,7 +167,7 @@ static int printEnvironment(FILE *log)
f8539f
         newenv[i] = environ[i];
f8539f
     }
f8539f
 
f8539f
-    qsort(newenv, length, sizeof(newenv[0]), envsort);
f8539f
+    g_qsort_with_data(newenv, length, sizeof(newenv[0]), envsort, NULL);
f8539f
 
f8539f
     for (i = 0; i < length; i++) {
f8539f
         /* Ignore the variables used to instruct the loader into
f8539f
diff --git a/tests/virstringtest.c b/tests/virstringtest.c
f8539f
index 6e697cc240..f4976890db 100644
f8539f
--- a/tests/virstringtest.c
f8539f
+++ b/tests/virstringtest.c
f8539f
@@ -89,10 +89,10 @@ testStringSortCompare(const void *opaque G_GNUC_UNUSED)
f8539f
     };
f8539f
     size_t i;
f8539f
 
f8539f
-    qsort(randlist, G_N_ELEMENTS(randlist), sizeof(randlist[0]),
f8539f
-          virStringSortCompare);
f8539f
-    qsort(randrlist, G_N_ELEMENTS(randrlist), sizeof(randrlist[0]),
f8539f
-          virStringSortRevCompare);
f8539f
+    g_qsort_with_data(randlist, G_N_ELEMENTS(randlist),
f8539f
+                      sizeof(randlist[0]), virStringSortCompare, NULL);
f8539f
+    g_qsort_with_data(randrlist, G_N_ELEMENTS(randrlist),
f8539f
+                      sizeof(randrlist[0]), virStringSortRevCompare, NULL);
f8539f
 
f8539f
     for (i = 0; i < G_N_ELEMENTS(randlist); i++) {
f8539f
         if (STRNEQ(randlist[i], sortlist[i])) {
f8539f
diff --git a/tools/virsh-checkpoint.c b/tools/virsh-checkpoint.c
f8539f
index 727de34abb..34bae34f9a 100644
f8539f
--- a/tools/virsh-checkpoint.c
f8539f
+++ b/tools/virsh-checkpoint.c
f8539f
@@ -526,7 +526,8 @@ virshCheckpointListFree(struct virshCheckpointList *checkpointlist)
f8539f
 
f8539f
 static int
f8539f
 virshChkSorter(const void *a,
f8539f
-               const void *b)
f8539f
+               const void *b,
f8539f
+               void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const struct virshChk *sa = a;
f8539f
     const struct virshChk *sb = b;
f8539f
@@ -594,9 +595,10 @@ virshCheckpointListCollect(vshControl *ctl,
f8539f
     }
f8539f
 
f8539f
     if (!(orig_flags & VIR_DOMAIN_CHECKPOINT_LIST_TOPOLOGICAL) &&
f8539f
-        checkpointlist->chks)
f8539f
-        qsort(checkpointlist->chks, checkpointlist->nchks,
f8539f
-              sizeof(*checkpointlist->chks), virshChkSorter);
f8539f
+        checkpointlist->chks) {
f8539f
+        g_qsort_with_data(checkpointlist->chks, checkpointlist->nchks,
f8539f
+                          sizeof(*checkpointlist->chks), virshChkSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     ret = g_steal_pointer(&checkpointlist);
f8539f
 
f8539f
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c
f8539f
index 89fdc7a050..a2c56fc090 100644
f8539f
--- a/tools/virsh-domain-monitor.c
f8539f
+++ b/tools/virsh-domain-monitor.c
f8539f
@@ -1483,7 +1483,9 @@ static const vshCmdInfo info_list[] = {
f8539f
 
f8539f
 /* compare domains, pack NULLed ones at the end */
f8539f
 static int
f8539f
-virshDomainSorter(const void *a, const void *b)
f8539f
+virshDomainSorter(const void *a,
f8539f
+                  const void *b,
f8539f
+                  void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virDomainPtr *da = (virDomainPtr *) a;
f8539f
     virDomainPtr *db = (virDomainPtr *) b;
f8539f
@@ -1741,9 +1743,10 @@ virshDomainListCollect(vshControl *ctl, unsigned int flags)
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->domains && list->ndomains)
f8539f
-        qsort(list->domains, list->ndomains, sizeof(*list->domains),
f8539f
-              virshDomainSorter);
f8539f
+    if (list->domains && list->ndomains) {
f8539f
+        g_qsort_with_data(list->domains, list->ndomains,
f8539f
+                          sizeof(*list->domains), virshDomainSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list if filter simulation deleted entries */
f8539f
     if (deleted)
f8539f
diff --git a/tools/virsh-host.c b/tools/virsh-host.c
f8539f
index 4116481978..6c14be865f 100644
f8539f
--- a/tools/virsh-host.c
f8539f
+++ b/tools/virsh-host.c
f8539f
@@ -300,7 +300,9 @@ static const vshCmdOptDef opts_freepages[] = {
f8539f
 };
f8539f
 
f8539f
 static int
f8539f
-vshPageSizeSorter(const void *a, const void *b)
f8539f
+vshPageSizeSorter(const void *a,
f8539f
+                  const void *b,
f8539f
+                  void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     unsigned int pa = *(unsigned int *)a;
f8539f
     unsigned int pb = *(unsigned int *)b;
f8539f
@@ -377,7 +379,8 @@ cmdFreepages(vshControl *ctl, const vshCmd *cmd)
f8539f
              * @pagesize array will contain duplicates. We should
f8539f
              * remove them otherwise not very nice output will be
f8539f
              * produced. */
f8539f
-            qsort(pagesize, nodes_cnt, sizeof(*pagesize), vshPageSizeSorter);
f8539f
+            g_qsort_with_data(pagesize, nodes_cnt,
f8539f
+                              sizeof(*pagesize), vshPageSizeSorter, NULL);
f8539f
 
f8539f
             for (i = 0; i < nodes_cnt - 1;) {
f8539f
                 if (pagesize[i] == pagesize[i + 1]) {
f8539f
diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c
f8539f
index 77c0fff847..09a3668438 100644
f8539f
--- a/tools/virsh-interface.c
f8539f
+++ b/tools/virsh-interface.c
f8539f
@@ -141,7 +141,9 @@ cmdInterfaceEdit(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshInterfaceSorter(const void *a, const void *b)
f8539f
+virshInterfaceSorter(const void *a,
f8539f
+                     const void *b,
f8539f
+                     void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virInterfacePtr *ia = (virInterfacePtr *) a;
f8539f
     virInterfacePtr *ib = (virInterfacePtr *) b;
f8539f
@@ -281,9 +283,10 @@ virshInterfaceListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->ifaces && list->nifaces)
f8539f
-        qsort(list->ifaces, list->nifaces,
f8539f
-              sizeof(*list->ifaces), virshInterfaceSorter);
f8539f
+    if (list->ifaces && list->nifaces) {
f8539f
+        g_qsort_with_data(list->ifaces, list->nifaces,
f8539f
+                          sizeof(*list->ifaces), virshInterfaceSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list if filter simulation deleted entries */
f8539f
     if (deleted)
f8539f
diff --git a/tools/virsh-network.c b/tools/virsh-network.c
f8539f
index 998e7e15e3..68c7543863 100644
f8539f
--- a/tools/virsh-network.c
f8539f
+++ b/tools/virsh-network.c
f8539f
@@ -791,7 +791,9 @@ cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshNetworkSorter(const void *a, const void *b)
f8539f
+virshNetworkSorter(const void *a,
f8539f
+                   const void *b,
f8539f
+                   void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNetworkPtr *na = (virNetworkPtr *) a;
f8539f
     virNetworkPtr *nb = (virNetworkPtr *) b;
f8539f
@@ -982,9 +984,10 @@ virshNetworkListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->nets && list->nnets)
f8539f
-        qsort(list->nets, list->nnets,
f8539f
-              sizeof(*list->nets), virshNetworkSorter);
f8539f
+    if (list->nets && list->nnets) {
f8539f
+        g_qsort_with_data(list->nets, list->nnets,
f8539f
+                          sizeof(*list->nets), virshNetworkSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list if filter simulation deleted entries */
f8539f
     if (deleted)
f8539f
@@ -1801,7 +1804,9 @@ static const vshCmdOptDef opts_network_dhcp_leases[] = {
f8539f
 };
f8539f
 
f8539f
 static int
f8539f
-virshNetworkDHCPLeaseSorter(const void *a, const void *b)
f8539f
+virshNetworkDHCPLeaseSorter(const void *a,
f8539f
+                            const void *b,
f8539f
+                            void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNetworkDHCPLeasePtr *lease1 = (virNetworkDHCPLeasePtr *) a;
f8539f
     virNetworkDHCPLeasePtr *lease2 = (virNetworkDHCPLeasePtr *) b;
f8539f
@@ -1840,7 +1845,8 @@ cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd)
f8539f
     }
f8539f
 
f8539f
     /* Sort the list according to MAC Address/IAID */
f8539f
-    qsort(leases, nleases, sizeof(*leases), virshNetworkDHCPLeaseSorter);
f8539f
+    g_qsort_with_data(leases, nleases,
f8539f
+                      sizeof(*leases), virshNetworkDHCPLeaseSorter, NULL);
f8539f
 
f8539f
     table = vshTableNew(_("Expiry Time"), _("MAC address"), _("Protocol"),
f8539f
                         _("IP address"), _("Hostname"), _("Client ID or DUID"),
f8539f
@@ -2068,7 +2074,9 @@ cmdNetworkPortDelete(vshControl *ctl, const vshCmd *cmd)
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-virshNetworkPortSorter(const void *a, const void *b)
f8539f
+virshNetworkPortSorter(const void *a,
f8539f
+                       const void *b,
f8539f
+                       void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNetworkPortPtr *na = (virNetworkPortPtr *) a;
f8539f
     virNetworkPortPtr *nb = (virNetworkPortPtr *) b;
f8539f
@@ -2129,9 +2137,10 @@ virshNetworkPortListCollect(vshControl *ctl,
f8539f
     list->nports = ret;
f8539f
 
f8539f
     /* sort the list */
f8539f
-    if (list->ports && list->nports)
f8539f
-        qsort(list->ports, list->nports,
f8539f
-              sizeof(*list->ports), virshNetworkPortSorter);
f8539f
+    if (list->ports && list->nports) {
f8539f
+        g_qsort_with_data(list->ports, list->nports,
f8539f
+                          sizeof(*list->ports), virshNetworkPortSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     success = true;
f8539f
 
f8539f
diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c
f8539f
index 82b8fb44fc..fb38fd7fcc 100644
f8539f
--- a/tools/virsh-nodedev.c
f8539f
+++ b/tools/virsh-nodedev.c
f8539f
@@ -183,7 +183,9 @@ virshNodeListLookup(int devid, bool parent, void *opaque)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshNodeDeviceSorter(const void *a, const void *b)
f8539f
+virshNodeDeviceSorter(const void *a,
f8539f
+                      const void *b,
f8539f
+                      void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNodeDevicePtr *na = (virNodeDevicePtr *) a;
f8539f
     virNodeDevicePtr *nb = (virNodeDevicePtr *) b;
f8539f
@@ -334,9 +336,10 @@ virshNodeDeviceListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->devices && list->ndevices)
f8539f
-        qsort(list->devices, list->ndevices,
f8539f
-              sizeof(*list->devices), virshNodeDeviceSorter);
f8539f
+    if (list->devices && list->ndevices) {
f8539f
+        g_qsort_with_data(list->devices, list->ndevices,
f8539f
+                          sizeof(*list->devices), virshNodeDeviceSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list if filter simulation deleted entries */
f8539f
     if (deleted)
f8539f
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c
f8539f
index 92b2b7b3bc..fa52d020e4 100644
f8539f
--- a/tools/virsh-nwfilter.c
f8539f
+++ b/tools/virsh-nwfilter.c
f8539f
@@ -220,7 +220,9 @@ cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshNWFilterSorter(const void *a, const void *b)
f8539f
+virshNWFilterSorter(const void *a,
f8539f
+                    const void *b,
f8539f
+                    void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNWFilterPtr *fa = (virNWFilterPtr *) a;
f8539f
     virNWFilterPtr *fb = (virNWFilterPtr *) b;
f8539f
@@ -323,9 +325,10 @@ virshNWFilterListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->filters && list->nfilters)
f8539f
-        qsort(list->filters, list->nfilters,
f8539f
-              sizeof(*list->filters), virshNWFilterSorter);
f8539f
+    if (list->filters && list->nfilters) {
f8539f
+        g_qsort_with_data(list->filters, list->nfilters,
f8539f
+                          sizeof(*list->filters), virshNWFilterSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list for not found filter objects */
f8539f
     if (deleted)
f8539f
@@ -644,7 +647,9 @@ cmdNWFilterBindingDumpXML(vshControl *ctl, const vshCmd *cmd)
f8539f
 
f8539f
 
f8539f
 static int
f8539f
-virshNWFilterBindingSorter(const void *a, const void *b)
f8539f
+virshNWFilterBindingSorter(const void *a,
f8539f
+                           const void *b,
f8539f
+                           void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virNWFilterBindingPtr *fa = (virNWFilterBindingPtr *) a;
f8539f
     virNWFilterBindingPtr *fb = (virNWFilterBindingPtr *) b;
f8539f
@@ -702,9 +707,10 @@ virshNWFilterBindingListCollect(vshControl *ctl,
f8539f
     list->nbindings = ret;
f8539f
 
f8539f
     /* sort the list */
f8539f
-    if (list->bindings && list->nbindings > 1)
f8539f
-        qsort(list->bindings, list->nbindings,
f8539f
-              sizeof(*list->bindings), virshNWFilterBindingSorter);
f8539f
+    if (list->bindings && list->nbindings > 1) {
f8539f
+        g_qsort_with_data(list->bindings, list->nbindings,
f8539f
+                          sizeof(*list->bindings), virshNWFilterBindingSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     success = true;
f8539f
 
f8539f
diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c
f8539f
index 5803530d79..36f00cf643 100644
f8539f
--- a/tools/virsh-pool.c
f8539f
+++ b/tools/virsh-pool.c
f8539f
@@ -814,7 +814,9 @@ cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshStoragePoolSorter(const void *a, const void *b)
f8539f
+virshStoragePoolSorter(const void *a,
f8539f
+                       const void *b,
f8539f
+                       void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virStoragePoolPtr *pa = (virStoragePoolPtr *) a;
f8539f
     virStoragePoolPtr *pb = (virStoragePoolPtr *) b;
f8539f
@@ -1005,9 +1007,10 @@ virshStoragePoolListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->pools && list->npools)
f8539f
-        qsort(list->pools, list->npools,
f8539f
-              sizeof(*list->pools), virshStoragePoolSorter);
f8539f
+    if (list->pools && list->npools) {
f8539f
+        g_qsort_with_data(list->pools, list->npools,
f8539f
+                          sizeof(*list->pools), virshStoragePoolSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list if filter simulation deleted entries */
f8539f
     if (deleted)
f8539f
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c
f8539f
index 694e16c5cb..e54712ba78 100644
f8539f
--- a/tools/virsh-secret.c
f8539f
+++ b/tools/virsh-secret.c
f8539f
@@ -399,7 +399,9 @@ cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshSecretSorter(const void *a, const void *b)
f8539f
+virshSecretSorter(const void *a,
f8539f
+                  const void *b,
f8539f
+                  void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virSecretPtr *sa = (virSecretPtr *) a;
f8539f
     virSecretPtr *sb = (virSecretPtr *) b;
f8539f
@@ -509,9 +511,10 @@ virshSecretListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->secrets && list->nsecrets)
f8539f
-        qsort(list->secrets, list->nsecrets,
f8539f
-              sizeof(*list->secrets), virshSecretSorter);
f8539f
+    if (list->secrets && list->nsecrets) {
f8539f
+        g_qsort_with_data(list->secrets, list->nsecrets,
f8539f
+                          sizeof(*list->secrets), virshSecretSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     /* truncate the list for not found secret objects */
f8539f
     if (deleted)
f8539f
diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c
f8539f
index c85258c09a..2049872322 100644
f8539f
--- a/tools/virsh-snapshot.c
f8539f
+++ b/tools/virsh-snapshot.c
f8539f
@@ -982,7 +982,9 @@ virshSnapshotListFree(struct virshSnapshotList *snaplist)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshSnapSorter(const void *a, const void *b)
f8539f
+virshSnapSorter(const void *a,
f8539f
+                const void *b,
f8539f
+                void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     const struct virshSnap *sa = a;
f8539f
     const struct virshSnap *sb = b;
f8539f
@@ -1232,7 +1234,7 @@ virshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
f8539f
          * still in list.  We mark known descendants by clearing
f8539f
          * snaps[i].parents.  Sorry, this is O(n^3) - hope your
f8539f
          * hierarchy isn't huge.  XXX Is it worth making O(n^2 log n)
f8539f
-         * by using qsort and bsearch?  */
f8539f
+         * by using g_qsort_with_data and bsearch?  */
f8539f
         if (start_index < 0) {
f8539f
             vshError(ctl, _("snapshot %1$s disappeared from list"), fromname);
f8539f
             goto cleanup;
f8539f
@@ -1312,8 +1314,8 @@ virshSnapshotListCollect(vshControl *ctl, virDomainPtr dom,
f8539f
     }
f8539f
     if (!(orig_flags & VIR_DOMAIN_SNAPSHOT_LIST_TOPOLOGICAL) &&
f8539f
         snaplist->snaps && snaplist->nsnaps) {
f8539f
-        qsort(snaplist->snaps, snaplist->nsnaps, sizeof(*snaplist->snaps),
f8539f
-              virshSnapSorter);
f8539f
+        g_qsort_with_data(snaplist->snaps, snaplist->nsnaps,
f8539f
+                          sizeof(*snaplist->snaps), virshSnapSorter, NULL);
f8539f
     }
f8539f
     snaplist->nsnaps -= deleted;
f8539f
 
f8539f
diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c
f8539f
index 9a2b21d3f3..329ca3a66c 100644
f8539f
--- a/tools/virsh-volume.c
f8539f
+++ b/tools/virsh-volume.c
f8539f
@@ -1200,7 +1200,9 @@ cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
f8539f
 }
f8539f
 
f8539f
 static int
f8539f
-virshStorageVolSorter(const void *a, const void *b)
f8539f
+virshStorageVolSorter(const void *a,
f8539f
+                      const void *b,
f8539f
+                      void *opaque G_GNUC_UNUSED)
f8539f
 {
f8539f
     virStorageVolPtr *va = (virStorageVolPtr *) a;
f8539f
     virStorageVolPtr *vb = (virStorageVolPtr *) b;
f8539f
@@ -1299,8 +1301,10 @@ virshStorageVolListCollect(vshControl *ctl,
f8539f
 
f8539f
  finished:
f8539f
     /* sort the list */
f8539f
-    if (list->vols && list->nvols)
f8539f
-        qsort(list->vols, list->nvols, sizeof(*list->vols), virshStorageVolSorter);
f8539f
+    if (list->vols && list->nvols) {
f8539f
+        g_qsort_with_data(list->vols, list->nvols,
f8539f
+                          sizeof(*list->vols), virshStorageVolSorter, NULL);
f8539f
+    }
f8539f
 
f8539f
     if (deleted)
f8539f
         VIR_SHRINK_N(list->vols, list->nvols, deleted);
f8539f
-- 
f8539f
2.43.0
f8539f