[qsort] Fix O(N^2) behavior if all array elements are the same

Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11327

Reported as https://github.com/noporpoise/sort_r/issues/7
This commit is contained in:
Behdad Esfahbod 2018-11-10 01:56:37 -05:00
parent b308aaccf0
commit 3a9fa8c026
2 changed files with 11 additions and 4 deletions

View File

@ -356,7 +356,12 @@ hb_bsearch_r (const void *key, const void *base,
} }
/* From https://github.com/noporpoise/sort_r */ /* From https://github.com/noporpoise/sort_r
* With following modifications:
*
* 10 November 2018:
* https://github.com/noporpoise/sort_r/issues/7
*/
/* Isaac Turner 29 April 2014 Public Domain */ /* Isaac Turner 29 April 2014 Public Domain */
@ -412,7 +417,7 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w,
/* Use median of first, middle and last items as pivot */ /* Use median of first, middle and last items as pivot */
char *x, *y, *xend, ch; char *x, *y, *xend, ch;
char *pl, *pr; char *pl, *pm, *pr;
char *last = b+w*(nel-1), *tmp; char *last = b+w*(nel-1), *tmp;
char *l[3]; char *l[3];
l[0] = b; l[0] = b;
@ -434,13 +439,15 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w,
pr = last; pr = last;
while(pl < pr) { while(pl < pr) {
for(; pl < pr; pl += w) { pm = pl+((pr-pl+1)>>1);
for(; pl < pm; pl += w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) { if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pr -= w; /* pivot now at pl */ pr -= w; /* pivot now at pl */
break; break;
} }
} }
for(; pl < pr; pr -= w) { pm = pl+((pr-pl)>>1);
for(; pm < pr; pr -= w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) { if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pl += w; /* pivot now at pr */ pl += w; /* pivot now at pr */
break; break;