[util] Fix an out-by-one in QF_bsearch_r

And rename _bsearch to QF_bsearch_r since that's far less confusing.
Also, update the test to make it possible for valgrind to detect the
out-by-one. The problem was found when trying to remove components from
an entity when using subpools.
This commit is contained in:
Bill Currie 2023-03-05 15:22:01 +09:00
parent 370c36f6cc
commit 76ac446156
4 changed files with 19 additions and 13 deletions

View file

@ -35,7 +35,7 @@
typedef int (*__compar_d_fn_t)(const void *, const void *, void *); typedef int (*__compar_d_fn_t)(const void *, const void *, void *);
#endif #endif
void *_bsearch(const void *key, const void *base, size_t nmemb, size_t size, void *QF_bsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg); __compar_d_fn_t cmp, void *arg);
#endif// quicksort_h #endif// quicksort_h

View file

@ -109,7 +109,7 @@ size_t strndup (const char *str, size_t len);
#ifndef HAVE_BSEARCH_R #ifndef HAVE_BSEARCH_R
# include "bsearch.h" # include "bsearch.h"
# define bsearch_r _bsearch # define bsearch_r QF_bsearch_r
#endif #endif
#ifndef HAVE_QSORT_R #ifndef HAVE_QSORT_R

View file

@ -63,13 +63,12 @@ void *fbsearch_r (const void *key, const void *_base, size_t nmemb, size_t size,
} }
void * void *
_bsearch(const void *key, const void *_base, size_t nmemb, size_t size, QF_bsearch_r(const void *key, const void *_base, size_t nmemb, size_t size,
__compar_d_fn_t cmp, void *arg) __compar_d_fn_t cmp, void *arg)
{ {
// fuzzy bsearh
const char *base = (const char *) _base; const char *base = (const char *) _base;
unsigned left = 0; unsigned left = 0;
unsigned right = nmemb; unsigned right = nmemb - 1;
unsigned mid; unsigned mid;
const void *p = 0; const void *p = 0;
int c; int c;

View file

@ -29,16 +29,19 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "QF/fbsearch.h" #include "QF/fbsearch.h"
#include "bsearch.h" #include "bsearch.h"
// will be prefix-summed // will be prefix-summed
int data[] = { int srcdata[] = {
2, 1, 3, 1, 2, 2, 5, 4, 2, 1, 3, 1, 2, 2, 5, 4,
2, 1, 3, 1, 2, 2, 5, 4, 2, 1, 3, 1, 2, 2, 5, 4,
}; };
#define nele ((int) (sizeof (data) / sizeof (data[0]))) #define nele ((int) (sizeof (srcdata) / sizeof (srcdata[0])))
int *data;
static int static int
compare (const void *a, const void *b) compare (const void *a, const void *b)
@ -83,6 +86,9 @@ main(int argc, const char **argv)
int ret = 0; int ret = 0;
int *p; int *p;
data = malloc (nele * sizeof (int));
memcpy (data, srcdata, nele * sizeof (int));
for (int i = 1; i < nele; i++) { for (int i = 1; i < nele; i++) {
data[i] += data[i - 1]; data[i] += data[i - 1];
} }
@ -99,18 +105,19 @@ main(int argc, const char **argv)
ret |= 1; ret |= 1;
} }
if (p && i == *p) { if (p && i == *p) {
p = _bsearch (&i, data, nele, sizeof (int), compared, 0); p = QF_bsearch_r (&i, data, nele, sizeof (int), compared, 0);
if (!p || *p != i) { if (!p || *p != i) {
printf ("_bsearch did not find %d, but should have\n", i); printf ("QF_bsearch_r did not find %d, but should have\n", i);
ret |= 1; ret |= 1;
} }
} else { } else {
p = _bsearch (&i, data, nele, sizeof (int), compared, 0); p = QF_bsearch_r (&i, data, nele, sizeof (int), compared, 0);
if (p) { if (p) {
printf ("_bsearch found %d, but should not have\n", i); printf ("QF_bsearch_r found %d, but should not have\n", i);
ret |= 1; ret |= 1;
} }
} }
} }
free (data);
return ret; return ret;
} }