Fix a crash when iterating over a hash and removing its elements.

Obtained from:	OpenBSD
This commit is contained in:
Xin LI 2009-03-28 06:30:43 +00:00
parent 3130c353f8
commit 213bceeead
2 changed files with 21 additions and 11 deletions
lib/libc/db/hash

@ -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);
}

@ -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;