libc qsort(3): stop aliasing.

Qsort swap code aliases the sorted array elements to ints and longs in
order to do swap by machine words.  Unfortunately this breaks with the
full code optimization, e.g. LTO.

See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83201 which seems to
reference code directly copied from libc/stdlib/qsort.c.

PR:	228780
Reported by:	mliska@suse.cz
Reviewed by:	brooks
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
Differential revision:	https://reviews.freebsd.org/D15714
This commit is contained in:
Konstantin Belousov 2018-06-10 17:54:44 +00:00
parent 7e53aaedd3
commit 6609261660

View File

@ -43,53 +43,27 @@ typedef int cmp_t(void *, const void *, const void *);
typedef int cmp_t(const void *, const void *);
#endif
static inline char *med3(char *, char *, char *, cmp_t *, void *);
static inline void swapfunc(char *, char *, size_t, int, int);
#define MIN(a, b) ((a) < (b) ? a : b)
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) { \
size_t i = (n) / sizeof (TYPE); \
TYPE *pi = (TYPE *) (parmi); \
TYPE *pj = (TYPE *) (parmj); \
do { \
TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(TYPE, a, es) swaptype_ ## TYPE = \
((char *)a - (char *)0) % sizeof(TYPE) || \
es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
static inline void
swapfunc(char *a, char *b, size_t n, int swaptype_long, int swaptype_int)
swapfunc(char *a, char *b, size_t es)
{
if (swaptype_long <= 1)
swapcode(long, a, b, n)
else if (swaptype_int <= 1)
swapcode(int, a, b, n)
else
swapcode(char, a, b, n)
char t;
do {
t = *a;
*a++ = *b;
*b++ = t;
} while (--es > 0);
}
#define swap(a, b) \
if (swaptype_long == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else if (swaptype_int == 0) { \
int t = *(int *)(a); \
*(int *)(a) = *(int *)(b); \
*(int *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype_long, swaptype_int)
#define vecswap(a, b, n) \
if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int)
if ((n) > 0) swapfunc(a, b, n)
#ifdef I_AM_QSORT_R
#define CMP(t, x, y) (cmp((t), (x), (y)))
@ -121,17 +95,16 @@ qsort(void *a, size_t n, size_t es, cmp_t *cmp)
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
size_t d1, d2;
int cmp_result;
int swaptype_long, swaptype_int, swap_cnt;
int swap_cnt;
loop: SWAPINIT(long, a, es);
SWAPINIT(int, a, es);
loop:
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
swapfunc(pl, pl - es, es);
return;
}
pm = (char *)a + (n / 2) * es;
@ -147,7 +120,7 @@ loop: SWAPINIT(long, a, es);
}
pm = med3(pl, pm, pn, cmp, thunk);
}
swap(a, pm);
swapfunc(a, pm, es);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
@ -155,7 +128,7 @@ loop: SWAPINIT(long, a, es);
while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pa, pb);
swapfunc(pa, pb, es);
pa += es;
}
pb += es;
@ -163,14 +136,14 @@ loop: SWAPINIT(long, a, es);
while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pc, pd);
swapfunc(pc, pd, es);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
swapfunc(pb, pc, es);
swap_cnt = 1;
pb += es;
pc -= es;
@ -180,7 +153,7 @@ loop: SWAPINIT(long, a, es);
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
swapfunc(pl, pl - es, es);
return;
}