summaryrefslogtreecommitdiffstats
path: root/lib/libc/db
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2009-03-28 06:30:43 +0000
committerdelphij <delphij@FreeBSD.org>2009-03-28 06:30:43 +0000
commitbe23f69f403b512b59926d78baae02cd2fb18778 (patch)
treef5ce199c5fb18974683a6436371f31ef3dd61245 /lib/libc/db
parent7a713ce8b411c402e521967c5c26f028adfb6a99 (diff)
downloadFreeBSD-src-be23f69f403b512b59926d78baae02cd2fb18778.zip
FreeBSD-src-be23f69f403b512b59926d78baae02cd2fb18778.tar.gz
Fix a crash when iterating over a hash and removing its elements.
Obtained from: OpenBSD
Diffstat (limited to 'lib/libc/db')
-rw-r--r--lib/libc/db/hash/hash.c24
-rw-r--r--lib/libc/db/hash/hash_page.c8
2 files changed, 21 insertions, 11 deletions
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
index 925f5c6..e333185 100644
--- a/lib/libc/db/hash/hash.c
+++ b/lib/libc/db/hash/hash.c
@@ -539,8 +539,7 @@ hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
hashp = (HTAB *)dbp->internal;
if (flag && flag != R_NOOVERWRITE) {
- hashp->error = EINVAL;
- errno = EINVAL;
+ hashp->error = errno = EINVAL;
return (ERROR);
}
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
@@ -719,7 +718,7 @@ hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
hashp->cndx = 1;
hashp->cpage = NULL;
}
-
+ next_bucket:
for (bp = NULL; !bp || !bp[0]; ) {
if (!(bufp = hashp->cpage)) {
for (bucket = hashp->cbucket;
@@ -738,8 +737,18 @@ hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
hashp->cbucket = -1;
return (ABNORMAL);
}
- } else
+ } else {
bp = (u_int16_t *)hashp->cpage->page;
+ if (flag == R_NEXT) {
+ hashp->cndx += 2;
+ if (hashp->cndx > bp[0]) {
+ hashp->cpage = NULL;
+ hashp->cbucket++;
+ hashp->cndx = 1;
+ goto next_bucket;
+ }
+ }
+ }
#ifdef DEBUG
assert(bp);
@@ -767,13 +776,6 @@ hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
data->size = bp[ndx] - bp[ndx + 1];
- ndx += 2;
- if (ndx > bp[0]) {
- hashp->cpage = NULL;
- hashp->cbucket++;
- hashp->cndx = 1;
- } else
- hashp->cndx = ndx;
}
return (SUCCESS);
}
diff --git a/lib/libc/db/hash/hash_page.c b/lib/libc/db/hash/hash_page.c
index e34b30f..f1cde8f 100644
--- a/lib/libc/db/hash/hash_page.c
+++ b/lib/libc/db/hash/hash_page.c
@@ -155,6 +155,14 @@ __delpair(HTAB *hashp, BUFHEAD *bufp, int ndx)
bp[i - 1] = bp[i + 1] + pairlen;
}
}
+ if (ndx == hashp->cndx) {
+ /*
+ * We just removed pair we were "pointing" to.
+ * By moving back the cndx we ensure subsequent
+ * hash_seq() calls won't skip over any entries.
+ */
+ hashp->cndx -= 2;
+ }
}
/* Finally adjust the page data */
bp[n] = OFFSET(bp) + pairlen;
OpenPOWER on IntegriCloud