Index: include/stdlib.h =================================================================== --- include/stdlib.h +++ include/stdlib.h @@ -297,8 +297,8 @@ #endif int mkostemp(char *, int); int mkostemps(char *, int, int); -void qsort_r(void *, size_t, size_t, void *, - int (*)(void *, const void *, const void *)); +void qsort_r(void *, size_t, size_t, + int (*)(const void *, const void *, void *), void *); int radixsort(const unsigned char **, int, const unsigned char *, unsigned); void *reallocarray(void *, size_t, size_t) __result_use_check @@ -319,6 +319,19 @@ __uint64_t strtouq(const char *, char **, int); +/* + * Attempt to trap calls of the historical qsort_r() function. The order + * of the last two arguments of this function have changed. If the last + * argument matches the type of the traditional comparator function, + * call an integer instead, which will generate a compiler error. + */ +#if defined(__generic) && !defined(__cplusplus) +extern int __calling_qsort_r_incorrectly; +#define qsort_r(base, nel, width, compar, arg) \ + __generic(arg, int (*)(void *, const void *, const void *), \ + __calling_qsort_r_incorrectly, qsort_r)(base, nel, width, compar, arg) +#endif + extern char *suboptarg; /* getsubopt(3) external variable */ #endif /* __BSD_VISIBLE */ Index: lib/libc/gen/scandir-compat11.c =================================================================== --- lib/libc/gen/scandir-compat11.c +++ lib/libc/gen/scandir-compat11.c @@ -60,8 +60,8 @@ #define SELECT(x) select(x) #endif -static int freebsd11_alphasort_thunk(void *thunk, const void *p1, - const void *p2); +static int freebsd11_alphasort_thunk(const void *p1, const void *p2, + void *thunk); int #ifdef I_AM_SCANDIR_B @@ -129,7 +129,7 @@ (void*)dcomp); #else qsort_r(names, numitems, sizeof(struct freebsd11_dirent *), - &dcomp, freebsd11_alphasort_thunk); + freebsd11_alphasort_thunk, &dcomp); #endif *namelist = names; return (numitems); @@ -155,7 +155,7 @@ } static int -freebsd11_alphasort_thunk(void *thunk, const void *p1, const void *p2) +freebsd11_alphasort_thunk(const void *p1, const void *p2, void *thunk) { int (*dc)(const struct freebsd11_dirent **, const struct freebsd11_dirent **); Index: lib/libc/gen/scandir.c =================================================================== --- lib/libc/gen/scandir.c +++ lib/libc/gen/scandir.c @@ -57,7 +57,7 @@ #define SELECT(x) select(x) #endif -static int alphasort_thunk(void *thunk, const void *p1, const void *p2); +static int alphasort_thunk(const void *p1, const void *p2, void *thunk); int #ifdef I_AM_SCANDIR_B @@ -121,7 +121,7 @@ qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp); #else qsort_r(names, numitems, sizeof(struct dirent *), - &dcomp, alphasort_thunk); + alphasort_thunk, &dcomp); #endif *namelist = names; return (numitems); @@ -146,7 +146,7 @@ } static int -alphasort_thunk(void *thunk, const void *p1, const void *p2) +alphasort_thunk(const void *p1, const void *p2, void *thunk) { int (*dc)(const struct dirent **, const struct dirent **); Index: lib/libc/stdlib/Makefile.inc =================================================================== --- lib/libc/stdlib/Makefile.inc +++ lib/libc/stdlib/Makefile.inc @@ -11,8 +11,8 @@ getsubopt.c hcreate.c hcreate_r.c hdestroy_r.c heapsort.c heapsort_b.c \ hsearch_r.c imaxabs.c imaxdiv.c \ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \ - merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c quick_exit.c \ - radixsort.c rand.c \ + merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \ + quick_exit.c radixsort.c rand.c \ random.c reallocarray.c reallocf.c realpath.c remque.c \ set_constraint_handler_s.c strfmon.c strtoimax.c \ strtol.c strtold.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \ Index: lib/libc/stdlib/Symbol.map =================================================================== --- lib/libc/stdlib/Symbol.map +++ lib/libc/stdlib/Symbol.map @@ -49,7 +49,6 @@ lfind; mergesort; putenv; - qsort_r; qsort; radixsort; sradixsort; @@ -122,6 +121,7 @@ abort_handler_s; ignore_handler_s; set_constraint_handler_s; + qsort_r; }; FBSDprivate_1.0 { Index: lib/libc/stdlib/qsort.3 =================================================================== --- lib/libc/stdlib/qsort.3 +++ lib/libc/stdlib/qsort.3 @@ -32,7 +32,7 @@ .\" @(#)qsort.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd February 20, 2013 +.Dd September 8, 2018 .Dt QSORT 3 .Os .Sh NAME @@ -67,8 +67,8 @@ .Fa "void *base" .Fa "size_t nmemb" .Fa "size_t size" +.Fa "int \*[lp]*compar\*[rp]\*[lp]const void *, const void *, void *\*[rp]" .Fa "void *thunk" -.Fa "int \*[lp]*compar\*[rp]\*[lp]void *, const void *, const void *\*[rp]" .Fc .Ft int .Fo heapsort @@ -148,7 +148,7 @@ .Fn qsort , except that it takes an additional argument, .Fa thunk , -which is passed unchanged as the first argument to function pointed to +which is passed unchanged as the last argument to function pointed to .Fa compar . This allows the comparison function to access additional data without using global variables, and thus @@ -370,3 +370,9 @@ The variants of these functions that take blocks as arguments first appeared in Mac OS X. This implementation was created by David Chisnall. +.Pp +In +.Fx 13.0 , +the prototype of +.Fn qsort_r +was updated to match glibc. Index: lib/libc/stdlib/qsort.c =================================================================== --- lib/libc/stdlib/qsort.c +++ lib/libc/stdlib/qsort.c @@ -37,7 +37,9 @@ #include -#ifdef I_AM_QSORT_R +#if defined(I_AM_QSORT_R) +typedef int cmp_t(const void *, const void *, void *); +#elif defined(I_AM_QSORT_R_COMPAT) typedef int cmp_t(void *, const void *, const void *); #else typedef int cmp_t(const void *, const void *); @@ -65,7 +67,9 @@ #define vecswap(a, b, n) \ if ((n) > 0) swapfunc(a, b, n) -#ifdef I_AM_QSORT_R +#if defined(I_AM_QSORT_R) +#define CMP(t, x, y) (cmp((x), (y), (t))) +#elif defined(I_AM_QSORT_R_COMPAT) #define CMP(t, x, y) (cmp((t), (x), (y))) #else #define CMP(t, x, y) (cmp((x), (y))) @@ -73,7 +77,7 @@ static inline char * med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk -#ifndef I_AM_QSORT_R +#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) __unused #endif ) @@ -83,9 +87,12 @@ :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); } -#ifdef I_AM_QSORT_R +#if defined(I_AM_QSORT_R) void -qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) +(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) +#elif defined(I_AM_QSORT_R_COMPAT) +void +__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) #else #define thunk NULL void @@ -168,8 +175,10 @@ if (d1 <= d2) { /* Recurse on left partition, then iterate on right partition */ if (d1 > es) { -#ifdef I_AM_QSORT_R - qsort_r(a, d1 / es, es, thunk, cmp); +#if defined(I_AM_QSORT_R) + qsort_r(a, d1 / es, es, cmp, thunk); +#elif defined(I_AM_QSORT_R_COMPAT) + __qsort_r_compat(a, d1 / es, es, thunk, cmp); #else qsort(a, d1 / es, es, cmp); #endif @@ -184,8 +193,10 @@ } else { /* Recurse on right partition, then iterate on left partition */ if (d2 > es) { -#ifdef I_AM_QSORT_R - qsort_r(pn - d2, d2 / es, es, thunk, cmp); +#if defined(I_AM_QSORT_R) + qsort_r(pn - d2, d2 / es, es, cmp, thunk); +#elif defined(I_AM_QSORT_R_COMPAT) + __qsort_r_compat(pn - d2, d2 / es, es, thunk, cmp); #else qsort(pn - d2, d2 / es, es, cmp); #endif Index: lib/libc/stdlib/qsort_r.c =================================================================== --- lib/libc/stdlib/qsort_r.c +++ lib/libc/stdlib/qsort_r.c @@ -4,16 +4,5 @@ * * $FreeBSD$ */ -#include "block_abi.h" #define I_AM_QSORT_R #include "qsort.c" - -typedef DECLARE_BLOCK(int, qsort_block, const void *, const void *); - -void -qsort_b(void *base, size_t nel, size_t width, qsort_block compar) -{ - qsort_r(base, nel, width, compar, - (int (*)(void *, const void *, const void *)) - GET_BLOCK_FUNCTION(compar)); -} Index: lib/libc/stdlib/qsort_r_compat.c =================================================================== --- lib/libc/stdlib/qsort_r_compat.c +++ lib/libc/stdlib/qsort_r_compat.c @@ -2,10 +2,10 @@ * This file is in the public domain. Originally written by Garrett * A. Wollman. * - * $FreeBSD: head/lib/libc/stdlib/qsort_r.c 264143 2014-04-05 08:17:48Z theraven $ + * $FreeBSD: head/lib/libc/stdlib/qsort_r_compat.c 264143 2014-04-05 08:17:48Z theraven $ */ #include "block_abi.h" -#define I_AM_QSORT_R +#define I_AM_QSORT_R_COMPAT #include "qsort.c" typedef DECLARE_BLOCK(int, qsort_block, const void *, const void *); @@ -13,7 +13,9 @@ void qsort_b(void *base, size_t nel, size_t width, qsort_block compar) { - qsort_r(base, nel, width, compar, + __qsort_r_compat(base, nel, width, compar, (int (*)(void *, const void *, const void *)) GET_BLOCK_FUNCTION(compar)); } + +__sym_compat(qsort_r, __qsort_r_compat, FBSD_1.0); Index: lib/libproc/proc_sym.c =================================================================== --- lib/libproc/proc_sym.c +++ lib/libproc/proc_sym.c @@ -108,7 +108,7 @@ }; static int -symvalcmp(void *_thunk, const void *a1, const void *a2) +symvalcmp(const void *a1, const void *a2, void *_thunk) { GElf_Sym sym1, sym2; struct symsort_thunk *thunk; @@ -195,7 +195,7 @@ thunk.e = e; thunk.symtab = symtab; - qsort_r(symtab->index, nsyms, sizeof(u_int), &thunk, symvalcmp); + qsort_r(symtab->index, nsyms, sizeof(u_int), symvalcmp, &thunk); return (0); } Index: sys/compat/linuxkpi/common/src/linux_compat.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_compat.c +++ sys/compat/linuxkpi/common/src/linux_compat.c @@ -2059,7 +2059,7 @@ }; static inline int -linux_le_cmp(void *priv, const void *d1, const void *d2) +linux_le_cmp(const void *d1, const void *d2, void *priv) { struct list_head *le1, *le2; struct list_sort_thunk *thunk; @@ -2087,7 +2087,7 @@ ar[i++] = le; thunk.cmp = cmp; thunk.priv = priv; - qsort_r(ar, count, sizeof(struct list_head *), &thunk, linux_le_cmp); + qsort_r(ar, count, sizeof(struct list_head *), linux_le_cmp, &thunk); INIT_LIST_HEAD(head); for (i = 0; i < count; i++) list_add_tail(ar[i], head); Index: sys/dev/bhnd/nvram/bhnd_nvram_store_subr.c =================================================================== --- sys/dev/bhnd/nvram/bhnd_nvram_store_subr.c +++ sys/dev/bhnd/nvram/bhnd_nvram_store_subr.c @@ -59,8 +59,7 @@ #include "bhnd_nvram_storevar.h" -static int bhnd_nvstore_idx_cmp(void *ctx, - const void *lhs, const void *rhs); +static int bhnd_nvstore_idx_cmp(const void *lhs, const void *rhs, void *ctx); /** * Allocate and initialize a new path instance. @@ -198,7 +197,7 @@ /* sort function for bhnd_nvstore_index_prepare() */ static int -bhnd_nvstore_idx_cmp(void *ctx, const void *lhs, const void *rhs) +bhnd_nvstore_idx_cmp(const void *lhs, const void *rhs, void *ctx) { struct bhnd_nvram_store *sc; void *l_cookiep, *r_cookiep; @@ -259,8 +258,8 @@ BHND_NVSTORE_LOCK_ASSERT(sc, MA_OWNED); /* Sort the index table */ - qsort_r(index->cookiep, index->count, sizeof(index->cookiep[0]), sc, - bhnd_nvstore_idx_cmp); + qsort_r(index->cookiep, index->count, sizeof(index->cookiep[0]), + bhnd_nvstore_idx_cmp, sc); return (0); } Index: sys/dev/drm2/drm_linux_list_sort.c =================================================================== --- sys/dev/drm2/drm_linux_list_sort.c +++ sys/dev/drm2/drm_linux_list_sort.c @@ -38,7 +38,7 @@ }; static int -drm_le_cmp(void *priv, const void *d1, const void *d2) +drm_le_cmp(const void *d1, const void *d2, void *priv) { struct list_head *le1, *le2; struct drm_list_sort_thunk *thunk; @@ -69,7 +69,7 @@ ar[i++] = le; thunk.cmp = cmp; thunk.priv = priv; - qsort_r(ar, count, sizeof(struct list_head *), &thunk, drm_le_cmp); + qsort_r(ar, count, sizeof(struct list_head *), drm_le_cmp, &thunk); INIT_LIST_HEAD(head); for (i = 0; i < count; i++) list_add_tail(ar[i], head); Index: sys/libkern/qsort.c =================================================================== --- sys/libkern/qsort.c +++ sys/libkern/qsort.c @@ -36,7 +36,7 @@ #include #ifdef I_AM_QSORT_R -typedef int cmp_t(void *, const void *, const void *); +typedef int cmp_t(const void *, const void *, void *); #else typedef int cmp_t(const void *, const void *); #endif @@ -88,7 +88,7 @@ if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int) #ifdef I_AM_QSORT_R -#define CMP(t, x, y) (cmp((t), (x), (y))) +#define CMP(t, x, y) (cmp((x), (y), (t))) #else #define CMP(t, x, y) (cmp((x), (y))) #endif @@ -107,7 +107,7 @@ #ifdef I_AM_QSORT_R void -qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) +(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) #else #define thunk NULL void @@ -192,7 +192,7 @@ /* Recurse on left partition, then iterate on right partition */ if (d1 > es) { #ifdef I_AM_QSORT_R - qsort_r(a, d1 / es, es, thunk, cmp); + qsort_r(a, d1 / es, es, cmp, thunk); #else qsort(a, d1 / es, es, cmp); #endif @@ -208,7 +208,7 @@ /* Recurse on right partition, then iterate on left partition */ if (d2 > es) { #ifdef I_AM_QSORT_R - qsort_r(pn - d2, d2 / es, es, thunk, cmp); + qsort_r(pn - d2, d2 / es, es, cmp, thunk); #else qsort(pn - d2, d2 / es, es, cmp); #endif Index: sys/netgraph/ng_ppp.c =================================================================== --- sys/netgraph/ng_ppp.c +++ sys/netgraph/ng_ppp.c @@ -322,7 +322,7 @@ static void ng_ppp_frag_checkstale(node_p node); static void ng_ppp_frag_reset(node_p node); static void ng_ppp_mp_strategy(node_p node, int len, int *distrib); -static int ng_ppp_intcmp(void *latency, const void *v1, const void *v2); +static int ng_ppp_intcmp(const void *v1, const void *v2, void *latency); static struct mbuf *ng_ppp_addproto(struct mbuf *m, uint16_t proto, int compOK); static struct mbuf *ng_ppp_cutproto(struct mbuf *m, uint16_t *proto); static struct mbuf *ng_ppp_prepend(struct mbuf *m, const void *buf, int len); @@ -2319,8 +2319,8 @@ } /* Sort active links by latency */ - qsort_r(sortByLatency, - priv->numActiveLinks, sizeof(*sortByLatency), latency, ng_ppp_intcmp); + qsort_r(sortByLatency, priv->numActiveLinks, sizeof(*sortByLatency), + ng_ppp_intcmp, latency); /* Find the interval we need (add links in sortByLatency[] order) */ for (numFragments = 1; @@ -2404,7 +2404,7 @@ * Compare two integers */ static int -ng_ppp_intcmp(void *latency, const void *v1, const void *v2) +ng_ppp_intcmp(const void *v1, const void *v2, void *latency) { const int index1 = *((const int *) v1); const int index2 = *((const int *) v2); Index: sys/sys/libkern.h =================================================================== --- sys/sys/libkern.h +++ sys/sys/libkern.h @@ -162,8 +162,8 @@ void *memmem(const void *l, size_t l_len, const void *s, size_t s_len); void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); -void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, - int (*compar)(void *, const void *, const void *)); +void qsort_r(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *, void *), void *thunk); u_long random(void); int scanc(u_int, const u_char *, const u_char *, int); void srandom(u_long); @@ -189,6 +189,19 @@ char *strstr(const char *, const char *); int strvalid(const char *, size_t); +/* + * Attempt to trap calls of the historical qsort_r() function. The order + * of the last two arguments of this function have changed. If the last + * argument matches the type of the traditional comparator function, + * call an integer instead, which will generate a compiler error. + */ +#if defined(__generic) && !defined(__cplusplus) +extern int __calling_qsort_r_incorrectly; +#define qsort_r(base, nel, width, compar, arg) \ + __generic(arg, int (*)(void *, const void *, const void *), \ + __calling_qsort_r_incorrectly, qsort_r)(base, nel, width, compar, arg) +#endif + extern const uint32_t crc32_tab[]; static __inline uint32_t