config(1): Make sort order deterministic.

Ensure we break ties in every case.  This way, even though we use the
unstable qsort(3) library routine, the output is reproducible, no
matter what algorithm is behind qsort(3).

It would be nice if we could just use a stable sort function here,
but mergesort(3) is nonstandard, so we'd have to add it to
tools/compat, which is a big pain.

Instead, put a tie-breaking rule in every comparison function we use
with qsort, and abort() in the event of ties -- that way, we noisily
refuse to rely on unstable sort order.

While here, dispense with any question of integer overflow, and
sprinkle comments.

PR bin/58115
This commit is contained in:
riastradh 2024-04-05 00:43:42 +00:00
parent 68ac9d1eae
commit 6dc5a3c0cc
5 changed files with 56 additions and 17 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.108 2024/01/18 05:41:38 thorpej Exp $ */ /* $NetBSD: defs.h,v 1.109 2024/04/05 00:43:42 riastradh Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -207,6 +207,8 @@ struct attr {
/* "device class" */ /* "device class" */
const char *a_devclass; /* device class described */ const char *a_devclass; /* device class described */
struct where a_where; struct where a_where;
size_t a_idx; /* index to break sorting ties */
}; };
/* /*

View File

@ -1,4 +1,4 @@
/* $NetBSD: files.c,v 1.37 2020/03/07 19:26:13 christos Exp $ */ /* $NetBSD: files.c,v 1.38 2024/04/05 00:43:42 riastradh Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -45,7 +45,7 @@
#endif #endif
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: files.c,v 1.37 2020/03/07 19:26:13 christos Exp $"); __RCSID("$NetBSD: files.c,v 1.38 2024/04/05 00:43:42 riastradh Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <assert.h> #include <assert.h>
@ -281,9 +281,9 @@ cmpfiles(const void *a, const void *b)
if (sa < sb) if (sa < sb)
return -1; return -1;
else if (sa > sb) else if (sa > sb)
return 1; return +1;
else else
return 0; abort(); /* no ties possible */
} }
/* /*

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkioconf.c,v 1.35 2017/11/19 01:46:29 christos Exp $ */ /* $NetBSD: mkioconf.c,v 1.36 2024/04/05 00:43:42 riastradh Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -45,7 +45,7 @@
#endif #endif
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: mkioconf.c,v 1.35 2017/11/19 01:46:29 christos Exp $"); __RCSID("$NetBSD: mkioconf.c,v 1.36 2024/04/05 00:43:42 riastradh Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <err.h> #include <err.h>
@ -136,7 +136,12 @@ cforder(const void *a, const void *b)
n1 = (*(const struct devi * const *)a)->i_cfindex; n1 = (*(const struct devi * const *)a)->i_cfindex;
n2 = (*(const struct devi * const *)b)->i_cfindex; n2 = (*(const struct devi * const *)b)->i_cfindex;
return (n1 - n2); if (n1 < n2)
return -1;
else if (n1 > n2)
return +1;
else
abort(); /* no ties possible */
} }
static void static void

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkmakefile.c,v 1.72 2024/01/18 04:41:37 thorpej Exp $ */ /* $NetBSD: mkmakefile.c,v 1.73 2024/04/05 00:43:42 riastradh Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -45,7 +45,7 @@
#endif #endif
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: mkmakefile.c,v 1.72 2024/01/18 04:41:37 thorpej Exp $"); __RCSID("$NetBSD: mkmakefile.c,v 1.73 2024/04/05 00:43:42 riastradh Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <ctype.h> #include <ctype.h>
@ -413,6 +413,7 @@ emitallkobjscb(const char *name, void *v, void *arg)
return 0; return 0;
if (TAILQ_EMPTY(&a->a_files)) if (TAILQ_EMPTY(&a->a_files))
return 0; return 0;
a->a_idx = attridx;
attrbuf[attridx++] = a; attrbuf[attridx++] = a;
/* XXX nattrs tracking is not exact yet */ /* XXX nattrs tracking is not exact yet */
if (attridx == nattrs) { if (attridx == nattrs) {
@ -447,7 +448,21 @@ attrcmp(const void *l, const void *r)
{ {
const struct attr * const *a = l, * const *b = r; const struct attr * const *a = l, * const *b = r;
const int wa = (*a)->a_weight, wb = (*b)->a_weight; const int wa = (*a)->a_weight, wb = (*b)->a_weight;
return (wa > wb) ? -1 : (wa < wb) ? 1 : 0;
/*
* Higher-weight first; then, among equal weights, earlier
* index first.
*/
if (wa > wb)
return -1;
else if (wa < wb)
return +1;
else if ((*a)->a_idx < (*b)->a_idx)
return -1;
else if ((*a)->a_idx > (*b)->a_idx)
return +1;
else
abort(); /* no ties possible */
} }
static void static void

View File

@ -1,4 +1,4 @@
/* $NetBSD: pack.c,v 1.10 2015/09/12 19:11:13 joerg Exp $ */ /* $NetBSD: pack.c,v 1.11 2024/04/05 00:43:42 riastradh Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -45,7 +45,7 @@
#endif #endif
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: pack.c,v 1.10 2015/09/12 19:11:13 joerg Exp $"); __RCSID("$NetBSD: pack.c,v 1.11 2024/04/05 00:43:42 riastradh Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <stdlib.h> #include <stdlib.h>
@ -319,21 +319,38 @@ addlocs(const char **locs, int len)
/* /*
* Comparison function for qsort-by-locator-length, longest first. * Comparison function for qsort-by-locator-length, longest first.
* We rashly assume that subtraction of these lengths does not overflow. *
* In the event of equality, break ties by i_cfindex, which should be
* unique, obviating the need for a stable sort.
*/ */
static int static int
loclencmp(const void *a, const void *b) loclencmp(const void *a, const void *b)
{ {
const struct devi *const *d1p = a, *d1 = *d1p;
const struct devi *const *d2p = b, *d2 = *d2p;
const struct pspec *p1, *p2; const struct pspec *p1, *p2;
int l1, l2; int l1, l2;
p1 = (*(const struct devi * const *)a)->i_pspec; p1 = d1->i_pspec;
l1 = p1 != NULL ? p1->p_iattr->a_loclen : 0; l1 = p1 != NULL ? p1->p_iattr->a_loclen : 0;
p2 = (*(const struct devi * const *)b)->i_pspec; p2 = d2->i_pspec;
l2 = p2 != NULL ? p2->p_iattr->a_loclen : 0; l2 = p2 != NULL ? p2->p_iattr->a_loclen : 0;
return (l2 - l1); /*
* Longer locators first; among equal locator lengths, earliest
* index first.
*/
if (l2 < l1)
return -1;
else if (l2 > l1)
return +1;
else if (d2->i_cfindex > d1->i_cfindex)
return -1;
else if (d2->i_cfindex < d1->i_cfindex)
return +1;
else
abort(); /* no ties possible */
} }
static void static void